PDA

View Full Version : Faking fixed-point arithmetic



Johannes
04-03-2011, 17:19
Even though this is a big integer module, you can fake fixed-point arithmetic.

What you do is multiply all numbers with the base you're working in raised to the power of the number of digits you want to have after the radix point. For example, if I want to work in radix 10 with three digits after the radix point, my fixed-point factor is 10^3 which is 1000.


There are some pitfalls, and off the top of my head they are as follows.

Changing the radix while preserving any Big Integer would be... unadvisable. In the above example the number 1.000 (which is stored as 1000) would become 3E8 in hexadecimal. Those three decimals are gone and what remains has no connection to 1.000 or 1000.
The output format should have separators disabled (BigInt_SetInterval(0)) so that it's easy to insert a radix character for printing. Nope, programmed around that. Separate format settings for regular BigInt and fixed-point.
Multiplying two Big Integers will double the precision, so after each multiplication a division (with optional rounding) by the fixed-point factor should be performed.
Dividing two Big Integers removes the precision, so before each division a multiplication by the fixed-point factor should be performed.
The same goes for square root, and for cube root a multiplication by the fixed-point factor squared should be performed. In both cases before the actual calculation.
When raising a number to a power the result should be divided by fixed_point_factor^(power - 1), again with optional rounding, after calculation. (The power itself should not be "converted" to "fixed-point".) Disregard that last bit between parentheses. The power must also be a fixed-point value but the fraction is ignored.
When calculating the nth root the number should be multiplied by fixed_point_factor^(power - 1) before the calculation. (The power itself should not be "converted" to "fixed-point".) Same for the last bit between parentheses as directly above.
Even/odd checking, Fibonacci, factorial, permutations and combinations are meaningless in this situation. As is anything dealing with primes.
BigInt_Inc and BigInc_Dec work at the lowest level, so they become an increase or decrease by 1/fixed_point_factor.
You'll be pleased to know that adding and subtracting works just fine. :)

Also, as long as you don't change the radix during your calculations, you can work in any radix you like. So it's possible to work in radix three with five digits after the radix point. The number 21.20121 would be stored internally as the (decimal) integer 1719 while it means 7.732510288065843621399176954 (the underlined digits repeat forever) which is 2*3+1+2/3+0/9+1/27+2/81+1/243. The fixed-point factor would be 3^5 which is 243.

If there is a big interest in fixed-point arithmetic in combination with Big Integers, and nobody understands what I'm describing above :), I'll whip up an include script.

When I get back from my vacation, at the end of this month.

Johannes
12-04-2011, 15:27
Nearly had a heart attack just now. I'm working on a fixed-point arithmetic include script for BigInt and was writing an example script with some, erm, examples.

After the simple, boring, stuff I had the script set the number of digits to 1,000. Square root of 2, cube root of 2. And 1/10! seemed like a good idea. The result was 0.5 and 999 other digits. That was not the near-heart attack.

Rewrote the test as 1 divided by 2, then the result by 3, then the result by 4, etc. The result for 0.1666666666 divided by 4 was 4.041666666666. Yes, there's a "4" in the beginning there. That was the near heart-attack.

Luckily it turned out it was just the convert-internal-fixed-point-value-to-string function that was incorrect, not the BigInt module. What I had was this.

If Len(a)<=fxp_dgt Then a=RIGHT$(Repeat$(fxp_dgt,"0"+a),fxp_dgt+1)
What it should have been was this.

If Len(a)<=fxp_dgt Then a=RIGHT$(Repeat$(fxp_dgt,"0")+a,fxp_dgt+1)
(The closing parenthesis of the Repeat$ should be after the "0", not after the a.)

Man, I should find a hobby that's a little bit easier on my nerves. Maybe there's an opening at the bomb squad.

Johannes
12-04-2011, 16:35
This is what I whipped up so far. I'll include it in the next release of BigInt, as examples of what you can do with BigInt, but I reserve the right to not support any of this. I will certainly not expand this with any trig or log functions. (Too slow and fixed-point is useless for that kind of thing. Floating-point will be my next project. Some time.)

Having said that, bug reports and how-to questions are welcome.