tags:

views:

2469

answers:

9

I have a big number (integer, unsigned) stored in 2 variables (as you can see, the high and low part of number):

unsigned long long int high;
unsigned long long int low;

I know how to add or subtract some other that-kind of variable.

But I need to divide that-kind of numbers. How to do it? I know, I can subtract N times, but, maybe, there are more better solutions. ;-)

Language: C

+2  A: 

Have you looked at any large-number libraries, such as GNU MP BigNum?

eduffy
It's too `expensive` for that program ;-(
A: 

Hmm. I suppose if you have some headroom in "high", you could shift it all up one digit, divide high by the number, then add the remainder to the top remaining digit in low and divide low by the number, then shift everything back.

T.E.D.
A: 

Per my commenters below, my previous answer was stupid.

Quickly, my new answer would be that when I've tried to do this in the past, it almost always involved shifting, because it's the only operation that can be applied across multiple "words", if you will, and have it look the same as if it were one large word (with the exception of having to track carryover bits).

There are a couple different approaches to it, but I don't know of any better general direction than using shifts, unless your hardware has some special operations.

Ben Collins
I think OP wants to divide a (high, low) pair by another (high, low) pair, which is not quite so simple.
ephemient
That's not what he's talking about. High and low are the high- and low-order parts a single number that is too large to fit in just one unsigned long long int.
Tyler McHenry
Ah, you're right. I skimmed the question too fast and assumed I knew what he was asking.
Ben Collins
+1  A: 

Here's another library doing 128 bit arithmetic. GnuCash: Math128.

DoxaLogos
+2  A: 

I know, I can subtract N times, but, maybe, there are more better solutions.

Subtracting N times may be slow when N is large.

Better (i.e. more complicated but faster) would be shift-and-subtract, using the algorithm you learned to do long division of decimal numbers in elementary school.

[There may also be 3rd-party library and/or compiler-specific support for such numbers.]

ChrisW
Admirable understatement. ITYM "O(n) algorithms on 128-bit values? AAAAAAAAAAARGH!"
Steve Jessop
Yes, ICWYM. It's not that the idea's a non-starter, but it is a non-finisher.
ChrisW
+5  A: 

Yes. It will involve shifts, and I don't recommend doing that in C. This is one of those rare examples where assembler can still prove its value, easily making things run hundreds of times faster (And I don't think I'm exaggerating this.)

I don't claim total correctness, but the following should get you going :

(1) Initialize result to zero.

(2) Shift divisor as many bits as possible to the left, without letting it become greater than the dividend.

(3) Subtract shifted divisor from dividend and add one to result.

(4) Now shift divisor to the right until once again, it is less than the remaining dividend, and for each right-shift, left-shift result by one bit. Go back to (3) unless stopping condition is satisfied. (Stopping condition must be something like "divisor has become zero", but I'm not certain about that.)

It really feels great to get back to some REAL programming problems :-)

The stopping condition is "when you've shifted as many times as you initially left-shifted", otherwise the result wouldn't be sufficiently left-shifted.
ChrisW
You don't recommend shifts in C? I'm an asm-lover, but C seems up to shifting, in my opinion. I highly doubt you can write an ASM routine for division that's hundreds of times faster than the C version.
Nosredna
This is very interesting. Can you point to some document that explains the math behind this? (or explain it yourself if you like)
Jeff Meatball Yang
Thank to you, I found a solution in the net. Thanks.
A: 

You could implement a "BigInt" type algorithm that does divisions on string arrays. Create 1 string array for each high,low pair and do the division. Store the result in another string array, then convert back to high,low integer pair.

Since the language is C, the array would probably be a character array. Consider it analogous to the "string array" I was mentioning above.

Sev
If he took that approach, working in hexadecimal rather than decimal would probably be best.
Nosredna
A: 

You can do addition and subtraction of arbitrarily large binary objects using the assembler looping and "add/subtract with carry (adc/sbb)" instructions. You can implement the other operations using them. I've never investigated doing anything beyond those two personally.

Jay
A: 

If your processor (or your C library) has a fast 64-bit divide, you can break the 128-bit divide into pieces (the same way you'd do a 32-bit divide on processors that had 16-bit divisions).

By the way, there are all sorts of tricks you can use if you know what typical values will be for the dividend and divisor. What is the source of these numbers? If a lot of your cases can be solved quickly, it might be OK the occasional case takes a long time.

Also, if you can find cases where an approximate answer is OK, that opens the door to a lot of speedy approximations.

Nosredna
Ditto if the processor has a fast 32-bit divide, or a 16-bit divide (by using more, smaller, pieces).
ChrisW
Good point ChrisW. If there's any hardware to take advantage of, probably worth trying it. Does C do full 64 bit by 64 bit division nowadays?
Nosredna