#33548 - 10/08/10 12:58 PM
Re: Float Multiply Results
[Re: Raphael Lalonde Lefebvre]
|
OL Toddler
Registered: 04/21/10
Posts: 34
Loc: Vancouver
|
Did you spcifiy the number of decimal places to include in the result string - like floattostr(&x, 6)? I understand Planet Press can handle 8 decimals that's why so confused about the result... Besides, if I set 8 decimals as floattostr(&x, 8), I got result 2433.43115234...Not sure where the last server digits came from. I even used function (mul(&y, &z))instead of (&y * &z), but got the same result Again, I feel something wrong with strtofloat and floattostr. The number I have is 0.219011, but after strtofloat and floattostr(&y, 8), it shows 0.21901099...
Edited by xss (10/08/10 01:50 PM)
|
Top
|
|
|
|
#33555 - 10/11/10 10:14 AM
Re: Float Multiply Results
[Re: xss]
|
OL Expert
Registered: 03/06/03
Posts: 713
Loc: Swindon, England
|
You need to understand that floating point numbers (also known as reals or measures) are not designed to hold exact values. It is characteristic of their use that converting to a float and converting back again only gives you an answer that matches within the precision of the float variable.
In postscript, floats are typically (it apparently depends on the implementation) held as 32 bit values. Many implementations will conform to the IEEE 754-2008 binary-32 standard. This gives a 8 bit exponent and a 24 bit mantissa. These are binary values. Converting to decimal, the exponent goes to 10^38.23 and the mantiassa gives 7.2 decimal digits.
This means that you cannot expect accuracy of more that 7 significant figures when doing arithmetic on floats.
In your example 0.219011 x 11111.000 = 2433.431 is the best you can hope for. If you require higher precision you ought to do the sums externally to PlanetPress and import the results with your data.
Hope that helps
|
Top
|
|
|
|
#33559 - 10/12/10 11:29 AM
Re: Float Multiply Results
[Re: stuartg]
|
OL Toddler
Registered: 04/21/10
Posts: 34
Loc: Vancouver
|
Thanks a lot for your explanation, stuartg!
Now I understand that I have to seek solution outside of Planet Press...
|
Top
|
|
|
|
#33562 - 10/12/10 03:06 PM
Re: Float Multiply Results
[Re: xss]
|
OL Expert
Registered: 10/14/05
Posts: 4956
Loc: Objectif Lune Montreal
|
xss, I actually took up the challenge of writing a function that will allow us to multiply two floats together with the proper precision, and I believe I got it to work pretty well! What it does is that it simulates manual multiplications, as if you were multiplying two numbers manually on paper. The good old method that we no longer use ever since calculators and computers made us lazy! First, you will need to create a global variable and call it "arrayresults" (change both the display name and presstalk ID), make it type "Array - string", and set it's size to 100 or higher. Then, create a global function, and copy-pages the huge code below: function @LongMultiply(&ns1:string, &ns2:string, &numdecimals:integer):string % ----------------------------- % Function: @LongMultiply % By: Raphaël Lalonde Lefebvre % % This function multiplies two decimal numbers, passed as strings. Sometimes, % the multiplication doesn't provide an exact result when using floattostr or % strtofloat. Past a certain point, the precision is altered and becomes wrong. % This function is a workaround to this issue. % % The other use is to multiply BIG numbers. You normally cannot multiply % billions together. This function can be used for that! % % Parameters: &ns1: First number to multiply. It's actually a string. % &ns2: Second number to multiply. % &numdecimals: Specific number of decimals. If set to -1, it is % ignored. % % The result is a floating point number, unless two integers are multiplied, then % the result will be an integer. The result is actually returned as a String. % % You can increase the size of the &arrayresults array to handle extremely large % numbers. % % NOTE THAT THIS FUNCTION IS NOT OFFICIALLY SUPPORTED BY OBJECTIF LUNE. % IT IS PROVIDED "AS-IS", WITH NO GUARANTEES OF IT'S FUNCTIONALITY OR PERFORMANCE. % ----------------------------- define(&i, integer, 0) define(&j, integer, 0) define(&k, integer, 0) define(&l, integer, 0) define(&r, integer, 0) define(&res, string, '') define(&i1, integer, 0) define(&i2, integer, 0) define(&s, string, '') define(&total, string, '') define(&decimals, integer, 0) define(&largest, integer, 0) define(&sum, integer, 0) define(&Zeroes, integer, 0) define(&Negative, boolean, False)
% Negative or positive? if(((pos('-', &ns1) > 0) and (pos('-', &ns2) > 0)) or ((pos('-', &ns1) = 0) and (pos('-', &ns2) = 0))) &Negative := False elseif() &Negative := True endif()
% Calculate the number of digits after the decimals. if(pos('.', &ns1) > 0) &decimals := &decimals + (length(&ns1) - pos('.', &ns1)) endif() if(pos('.', &ns2) > 0) &decimals := &decimals + (length(&ns2) - pos('.', &ns2)) endif()
&ns1 := strip('.', &ns1) &ns2 := strip('.', &ns2)
for(&i, length(&ns2), -1, 1) &r := 0 &s := '' + left('00000000000000000000', &k) for(&j, length(&ns1), -1, 1) &i1 := strtoint(mid(&ns1, &j, 1)) &i2 := strtoint(mid(&ns2, &i, 1))
if((&i2 * &i1) > 9) &s := inttostr(strtoint(mid(inttostr((&i2 * &i1)+&r), length(inttostr((&i2 * &i1)+&r)),1)) ) + &s &r := strtoint(mid(inttostr((&i2 * &i1)+&r), length(inttostr((&i2 * &i1)+&r))-1,1)) elseif() &s := inttostr((&i2 * &i1) + &r) + &s &r := 0 endif() endfor()
if(&r > 0) &arrayresults[&k] := inttostr(&r) + &s elseif() &arrayresults[&k] := &s endif() &k := &k + 1 endfor()
% Add up everything. &total := '' &largest := length(&arrayresults[&k-1])
% Add zeroes. for(&i, 0, 1, &k-1) if(length(&arrayresults[&i]) < &largest) &arrayresults[&i] := left('00000000000000000000', &largest - length(&arrayresults[&i])) + &arrayresults[&i] endif() endfor()
&total := '' &r := 0 for(&i, &largest, -1, 1) &sum := 0 + &r for(&j, (&k-1), -1, 0) &sum := &sum + strtoint(mid(&arrayresults[&j], &i, 1)) endfor() if(&sum > 9) &total := mid(inttostr(&sum), length(inttostr(&sum)), 1) + &total &r := strtoint(mid(inttostr(&sum), length(inttostr(&sum))-1, 1)) elseif() &total := inttostr(&sum) + &total &r := 0 endif() endfor()
% Add the decimal point. &res := '' if(&decimals > 0) &j := 0 for(&i,length(&total), -1, 1) &res := mid(&total, &i, 1) + &res &j := &j + 1 if(&j = &decimals) &res := '.' + &res endif() endfor() elseif() &res := &total endif()
% Remove leading zeroes. for(&i, 1, 1, length(&res)) if(mid(&res, &i, 1) = '0') &Zeroes := &Zeroes + 1 elseif() &res := mid(&res, &Zeroes+1, length(&res) - (&Zeroes)) exit() endif() endfor()
% Put a zero if the '.' is the first thing in the string. if(mid(&res, 1, 1) = '.') &res := '0' + &res endif()
% Reset Zeroes counter. &Zeroes := 0
% Remove trailing zeroes. % Only do this if it's a floating point number. if(pos('.', &res) > 0) for(&i, length(&res), -1, 1) if(mid(&res, &i, 1) = '0') &Zeroes := &Zeroes + 1 elseif() &res := mid(&res, 1, length(&res) - (&Zeroes-1)) exit() endif() endfor()
% Add one last zero if the last character is a '.'. if(mid(&res, length(&res), 1) = '.') &res := &res + '0' endif() endif()
% Add the negative sign if needed. if(&Negative) &res := '-' + &res endif()
% Minimum and maximum number of decimals. if(&numdecimals > -1) if(pos('.', &res) > 0) &i := length(mid(&res, pos('.', &res)+1, length(&res) - pos('.', &res))) % Minimum. if(&i < &numdecimals) &res := &res + left('0000000000000000000000000000000000000000', &numdecimals - &i) endif() % Maximum. if(&i > &numdecimals) &res := mid(&res, 1, pos('.', &res)-1) + '.' + mid(&res, pos('.', &res)+1, &numdecimals) endif() % If it's zero, remove the '.'. if(&numdecimals = 0) &res := strip('.', &res) endif() elseif() if(&numdecimals > 0) &res := &res + '.' + left('0000000000000000000000000000000000000000', &numdecimals) endif() endif() endif()
&Result := &res endfunction()Then, you can call this function in a data selection. Example: =@LongMultiply('0.219011', '11111', -1) And that will give us the 2433.431221 that we're looking for. The "-1" is the number of decimals. By specifying -1, it means that there is no specified number of decimals. You can set it to the number of decimals that you want to display. Note that the function expects strings as the parameters, so you can use data selections as the parameters. Do not use strtofloat. Here's an example what it may look like: =@LongMultiply(@(1,1,20), @(2,1,20), -1) Note that this function is not an official solution, and therefore is not supported by Objectif Lune. It is provided as-is, with no guarantees of perfect functionality.That said, I've tested it with various numbers, both entire numbers, floating points and a mix of both, and it has been working fine so far! Hope that helps! Regards, Raphaël Lalonde Lefebvre
Edited by Raphael Lalonde Lefebvre (10/13/10 10:16 AM)
|
Top
|
|
|
|
#33568 - 10/12/10 07:37 PM
Re: Float Multiply Results
[Re: Raphael Lalonde Lefebvre]
|
OL Toddler
Registered: 04/21/10
Posts: 34
Loc: Vancouver
|
Hi Raphaël,
The function is great! I got all correct results. The only thing is if I can set how many decimals I want? I set "arrayresults" as 20, and I have 7 decimals instead of 6 such as 2433.4312210...
Thank you!
|
Top
|
|
|
|
#33577 - 10/13/10 12:12 PM
Re: Float Multiply Results
[Re: Raphael Lalonde Lefebvre]
|
OL Toddler
Registered: 04/21/10
Posts: 34
Loc: Vancouver
|
You are awesome, Raphaël!
I have the decimals I want. Thank you!
|
Top
|
|
|
|
|
|