Generalised floating point multiplication: Difference between revisions

From Rosetta Code
Content added Content deleted
m (Change sequence to be from -15 to 13)
m (a sequence of -7 to 21 will work here too.)
Line 13: Line 13:


{|class="wikitable" style="text-align: center; margin: 1em auto 1em auto;"
{|class="wikitable" style="text-align: center; margin: 1em auto 1em auto;"
|+ Calculate the terms for -15 to 13 in this sequence of calculations
|+ Calculate the terms for -7 to 21 in this sequence of calculations
|-
|-
! Number !! Term calculation !! Result
! Number !! Term calculation !! Result
|-
|-
| -15 || 111111111e63**2 x 81 + 2e135 - 1e126 || 1e144
| -7 || 111111111e63**2 x 81 + 2e135 - 1e126 || 1e144
|-
|-
| -14 || 111111111111111111e54**2 x 81 + 2e126 - 1e108 || 1e144
| -6 || 111111111111111111e54**2 x 81 + 2e126 - 1e108 || 1e144
|-
|-
| -13 || 111111111111111111111111111e45**2 x 81 + 2e117 - 1e90 || 1e144
| -5 || 111111111111111111111111111e45**2 x 81 + 2e117 - 1e90 || 1e144
|-
|-
| -12 || 111111111111111111111111111111111111e36**2 x 81 + 2e108 - 1e72 || 1e144
| -4 || 111111111111111111111111111111111111e36**2 x 81 + 2e108 - 1e72 || 1e144
|-
|-
| etc. || The last calculation will be with floating point numbers of more then 500 digits || 1e144
| etc. || The last calculation will be with floating point numbers of more then 500 digits || 1e144

Revision as of 13:51, 30 October 2011

Generalised floating point multiplication is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

If possible, define multiplication for floating point numbers where the digits are stored in an arbitrary base. eg. the digits cab be stored as binary, decimal, Binary-coded decimal, or even Balanced ternary.

Implement the code in a generalised form (such as a Template, Module or Mixin etc) that permits reusing of the code for different Bases.

If it is not possible to implement code in syntax of the specific language then:

  • note the reason.
  • perform test case using a built-in or external library.

Test case:

Use the Template to define Arbitrary precision multiplication on numbers stored in Binary Coded Decimal.

Calculate the terms for -7 to 21 in this sequence of calculations
Number Term calculation Result
-7 111111111e63**2 x 81 + 2e135 - 1e126 1e144
-6 111111111111111111e54**2 x 81 + 2e126 - 1e108 1e144
-5 111111111111111111111111111e45**2 x 81 + 2e117 - 1e90 1e144
-4 111111111111111111111111111111111111e36**2 x 81 + 2e108 - 1e72 1e144
etc. The last calculation will be with floating point numbers of more then 500 digits 1e144

Note: The results will always be 1e144.

The Template should successfully handle these multiplications in other bases.

ALGOL 68

Works with: ALGOL 68 version Revision 1 - one minor extension to language used - PRAGMA READ, similar to C's #include directive.
Works with: ALGOL 68G version Any - tested with release algol68g-2.3.2.

File: Mixin_Big_float_multiplication.a68 <lang algol68>OP * = (DIGIT a, DIGITS b)DIGITS: INITDIGITS a * b; OP * = (DIGITS a, DIGIT b)DIGITS: a * INITDIGITS b;

OP * = (DIGITS in a, in b)DIGITS:(

  1. Note: is cast really needed? eg. []STRUCTDIGIT(~) #
 []DIGIT a = digit OF []STRUCTDIGIT(digits OF in a);
 []DIGIT b = digit OF []STRUCTDIGIT(digits OF in b);
 [digit order + MSD in a+MSD in b: LSD in a+LSD in b]DIGIT a times b;
 DIGIT zero := digit OF (INITSTRUCTDIGIT 0);
 FOR place FROM LSD in a+LSD in b BY digit order TO LSD in a+MSD in b DO
   a times b[place] := zero
 OD;
 FOR place a FROM LSD in a BY digit order TO MSD in a DO
   DIGIT digit a = a[place a];
   DIGIT carry := zero;
   FOR place b FROM LSD in b BY digit order TO MSD in b DO
     DIGIT digit b = b[place b];
     REF DIGIT digit ab = a times b[place a + place b]; 
     IF digit carry THEN # used for big number arithmetic #
       MOID(carry := ( digit ab +:= carry ));
       DIGIT prod := digit a; 
       MOID(carry +:= ( prod *:= digit b ));
       MOID(carry +:= ( digit ab +:= prod ))
     ELSE
       DIGIT prod := digit a; 
       MOID(prod *:= digit b);
       MOID(digit ab +:= prod)
     FI
   OD;
   a times b[place a + MSD in b + digit order] := carry
 OD;
 INITDIGITS digits normalise(a times b)

);</lang>File: test_Big_float_BCD_multiplication.a68 <lang algol68>#!/usr/local/bin/a68g --script #

  1. A program to test abritary length BCD floating point addition. #

PR READ "prelude/general.a68" PR

INT digit width := 1; # define how decimal digits each "big" DIGIT is #


COMMENT

 Source code for Big_float_BCD_base, Mixin_Big_float_addition & subtraction is
 located at: http://rosettacode.org/wiki/Generalised_floating_point_addition%23ALGOL_68

END COMMENT

  1. include the basic axioms of the digits being used #

PR READ "Big_float_BCD_base.a68" PR PR READ "Mixin_Big_float_addition.a68" PR PR READ "Mixin_Big_float_subtraction.a68" PR

  1. Generalised multiplication #

PR READ "Mixin_Big_float_multiplication.a68" PR

test: (

 BIGREAL pattern = INITBIGREAL 111111111,
 INT pattern width = 9;
 BIGREAL
   sum := INITBIGREAL 0,
   shifted pattern := pattern,
   tiny := INITBIGREAL 2, # typically 0.000.....00002 #
   very tiny := INITBIGREAL -1;# typically 0.000.....00001 #
 INT start = -8;
 FOR term FROM start TO 20 DO
 # First make shifted pattern smaller by shifting right by the pattern width #
   digits OF shifted pattern := (digits OF shifted pattern)[@term*pattern width+1];
   digits OF tiny := (digits OF tiny)[@(term+start+1)*pattern width];
   digits OF very tiny := (digits OF very tiny)[@2*(term+1)*pattern width];
   MOID(sum +:= shifted pattern);
 # Manually multiply by 81 by repeated addition #
   BIGREAL prod := sum * sum * INITBIGREAL 81;
   BIGREAL total = prod + tiny + very tiny;
   IF term < -4 THEN
     print(( REPR sum,"**2 x 81 gives: ", REPR prod, 
           ", Plus:",REPR tiny, " + ",REPR very tiny, ", Gives: "))
   ELSE
     print((LSD prod - MSD prod + 1," digit test result: "))
   FI;
   printf(($g$, REPR total, $" => "b("Passed","Failed")"!"$, LSD total = MSD total, $l$))
 OD

)</lang> Output:

111111111e63**2 x 81 gives: 999999998000000001e126, Plus:2e135 + -1e126, Gives: 1e144 => Passed!
111111111111111111e54**2 x 81 gives: 999999999999999998000000000000000001e108, Plus:2e126 + -1e108, Gives: 1e144 => Passed!
111111111111111111111111111e45**2 x 81 gives: 999999999999999999999999998000000000000000000000000001e90, Plus:2e117 + -1e90, Gives: 1e144 => Passed!
111111111111111111111111111111111111e36**2 x 81 gives: 999999999999999999999999999999999998000000000000000000000000000000000001e72, Plus:2e108 + -1e72, Gives: 1e144 => Passed!
        +90 digit test result: 1e144 => Passed!
       +108 digit test result: 1e144 => Passed!
       +126 digit test result: 1e144 => Passed!
       +144 digit test result: 1e144 => Passed!
       +162 digit test result: 1e144 => Passed!
       +180 digit test result: 1e144 => Passed!
       +198 digit test result: 1e144 => Passed!
       +216 digit test result: 1e144 => Passed!
       +234 digit test result: 1e144 => Passed!
       +252 digit test result: 1e144 => Passed!
       +270 digit test result: 1e144 => Passed!
       +288 digit test result: 1e144 => Passed!
       +306 digit test result: 1e144 => Passed!
       +324 digit test result: 1e144 => Passed!
       +342 digit test result: 1e144 => Passed!
       +360 digit test result: 1e144 => Passed!
       +378 digit test result: 1e144 => Passed!
       +396 digit test result: 1e144 => Passed!
       +414 digit test result: 1e144 => Passed!
       +432 digit test result: 1e144 => Passed!
       +450 digit test result: 1e144 => Passed!
       +468 digit test result: 1e144 => Passed!
       +486 digit test result: 1e144 => Passed!
       +504 digit test result: 1e144 => Passed!
       +522 digit test result: 1e144 => Passed!