views:

95

answers:

3

I have a C# system using 160 bit numbers, stored in a BigInteger. I want to display these things on a circle, which means mapping the 0->2^160 range into the 0->2Pi range. How would I do this?

The approach that jumps instantly to mind is

BigInteger number;
angle = (number / pow(2, 160)) * TwoPi;

However, that has complexities because the division will truncate the result into an integer.

A: 

There are no 'complexities' because Math.Pow() returns a double. So as long as BigInteger has an (implicit) converson to double you're good to go.

Henk Holterman
It doesn't have any such conversion, which means that BigInteger/double is not legal code
Martin
Jeez, so it only has an explicit conversion.
Henk Holterman
+2  A: 

Ok, again, from the start.

Since your BigInteger is from 0 -> 2^160 it's smaller than a double, which can contain from 10^(-308) to 10^(+308).

There is an explicit conversion from BigInteger to double.

So you do this:

BigInteger number;
var angle = ((double)number / Math.Pow(2, 160)) * TwoPi;

I do know that you'll lose precision, but that shouldn't matter on the circle.

Snake
It's not an integer, it's a big integer. Which means that BigInteger/double isn't even valid code
Martin
that example code is still no good. When the number is divided by 2^160 it's going to be truncated, because you're using integers. Then you convert twopi (which obviously has a few decimal places) into an integer, which one again will truncate.
Martin
What about this version? :)
Snake
I just independently came up with this method, as you say it loses some accuracy but seems to be ok. Probably because I'm "only" using 160 bit identifiers, for bigger numbers it wouldn't work - but for this project I don't care :P
Martin
If you want a double result you have to live within the limits of double's precision. You can't cram 160 bits of information into a 64-bit result without losing at least 96 bits of "precision".
GregS
+1  A: 

I know nothing of C# or its big integers, so here's a stab in the dark:

Unless your display is about the size of a (round) football field you are going to have to accept that the precision of your display will be much less than is required to show any separation between numbers which are only 1 apart (or 10 or 100 or 10000000 or even 10^40 but you have to figure that out).

I would simply truncate my big integer, take the highest order 32 bits and treat them as an unsigned integer, then divide it by 2^32 to bring it into the range [0,1) (converting it to floating-point as I divide) and plot it that far round the circle.

I guess truncating the big integer to get the leftmost 32 bits is equivalent to dividing it by 2^128 but there might be a better bit-shifting approach or you may be able to simply grab the bits directly.

High Performance Mark
Taking the final 32 bits is fine. I was looking for advice on how to do that specifically for C# BigInteger
Martin