1

I am trying to calculate the value of (10^5.102103)%24 that is 10 raised to power 5.102103 modulus 24 in Java ?

Which is the best and accurate method to do because

int a;
double b;
int m;

Calculate (a^b)%m

Where a can be very large like upto 10^9

b can be any double or float value which can be large

and m is any Integer

Example ---How you can calculate the value of

(10^10002.3443)%10000007

I know Math.pow(a,b) function works for small a and b only

While BigInteger function Uses only modPow(a,b) where a and b should be integer only(Correct me if i am wrong)

Ira Singh
  • 13
  • 1
  • 5
  • 1
    Can you guarantee that `a^b` will be within range for a `double`? If so, use `Math.pow`. – Dawood ibn Kareem Nov 13 '14 at 03:36
  • I dont think Math.pow() can calculate such values – Ira Singh Nov 13 '14 at 03:37
  • You'd probably have to write your own algorithm. I haven't been able to find anything in any of the standard `math` libraries that will do this. – Dawood ibn Kareem Nov 13 '14 at 03:38
  • There was a C++ answer pertaining to this. The algorithm came from a crypto book: [Calculating pow(a,b) mod n](http://stackoverflow.com/questions/8496182/calculating-powa-b-mod-n) – Obicere Nov 13 '14 at 03:40
  • @Obicere No. That C++ question is about integral types. Here, the exponent is a `double`, which changes everything. – Dawood ibn Kareem Nov 13 '14 at 03:44
  • @DavidWallace modular arithmetic makes it a lot easier. It doesn't change "everything", it just means you have to calculate an extra part. pow(x, m+n) = pow(x, m)*pow(x, n). Combined with modular arithmetic and the first part it is easy to solve for the answer. – Obicere Nov 13 '14 at 03:50
  • @Obicere I probably should've written my answer to have `O(log(b))` multiplications, instead of `(int) b + 1`. – royhowie Nov 13 '14 at 04:04
  • @Obicere Yes it does. Try it. You'll get the wrong answer, just like royhowie's solution here. – Dawood ibn Kareem Nov 13 '14 at 04:10
  • @IraSingh: *Why* are you trying to do this? What's the application? It's a rather bizarre thing to want to do. (Given the rash of similar questions on SO recently, I strongly suspect this is a homework assignment or some other kind of challenge problem.) – Mark Dickinson Nov 13 '14 at 08:04
  • @MarkDickinson if it _is_ a homework assignment, I am prepared to bet that the professor doesn't know what he/she is doing. – Dawood ibn Kareem Nov 13 '14 at 09:36
  • @DavidWallace: Agreed. – Mark Dickinson Nov 13 '14 at 14:03

2 Answers2

3

Unfortunately, it's not possible using the normal Java data types to get a correct answer to this. If you use double to store the exponent, you introduce an error, because double won't store most decimal numbers exactly. When you write double b = 10002.3443; the number that is stored in b is actually 10002.34430000000065774656832218170166015625. Even though it looks like 10002.3443 when you print it, that's a trick of the way Java prints numbers - basically it chooses the decimal number with the least number of decimal places that would be represented by that double.

Now this difference looks insignificant. But the difference between 10^10002.3443 and 10^10002.34430000000065774656832218170166015625 is approximately 3.346 x 10^9990, which is a 9991-digit number. Now, what will this difference become when we apply the modulus operator?

(10^10002.34430000000065774656832218170166015625 % 10000007) - (10^10002.3443 % 10000007)
= (10^10002.34430000000065774656832218170166015625 - 10^10002.3443) % 10000007
= (3.346 x 10^9990) % 10000007 (approximately)

Now, it's anybody's guess what that actually comes to. But you've got a better chance of being struck by lightning than of getting the correct answer, if you use double at any point in the calculation.

The other option might be BigDecimal. But the problem is that 10^10002.3443 is irrational - it's not a terminating decimal, so it can't be represented correctly in a BigDecimal.

So Java doesn't have a data type that will allow you to perform the calculation that you want to perform.

You are going to have to invent your own data type, then work out how to do all the bit-crunching to implement exponentiation and modulus. This is a huge project, and I suggest you start out by getting yourself a PhD in mathematics.

(Note: Obviously, I am using ^ to indicate exponentiation and x to indicate multiplication in the above, even though this is not the normal Java convention)

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
  • I'm beginning to think there must be a numerical method for doing this, along with some clever switching back and forth between `BigDecimal` and `BigInteger`. Someone who's smarter than I am could possibly come up with a very complicated solution using some nasty mathematics. It's more one for the mathematicians than for the Java programmers. I feel sure I shall lose sleep over this. – Dawood ibn Kareem Nov 13 '14 at 11:23
0

Let's think back to discrete math!

Given y = a b (mod m), we know that

y = ((a mod m)^b) mod m

For example, if we have

a = 2, b = 6, m = 5

a raised to the power of b is 64. 64 mod m is 64 % 5 == 4. Let's check our algorithm:

4 == ((a mod m)^b) mod m
4 == ((2 mod 5)^6) mod 5
...
4 == 64 % 5
4 == 4

This doesn't really help us all too much (in its current form), so let's use modular arithmetic at every step to save the day.

int a = 10;
int m = 10000007;
double b = 10002.3443;
int holder = (int) b;
double delta = b - holder; // as close as we're going to get

int total = 1;

for (int i = 0; i < holder; i++) {
    total *= (a % m); // multiply by the modulus
    total %= m;       // take the modulus again
}

total *= (Math.round(Math.pow(a, delta)) % m);
total %= m;
royhowie
  • 11,075
  • 14
  • 50
  • 67
  • 1
    No, this doesn't work for fractional exponents. When you multiply that fractional part at the end, you need to take into account all the `m`s that you subtracted away by taking the modulus. But they're gone. So this is just about guaranteed to give the wrong answer. – Dawood ibn Kareem Nov 13 '14 at 04:11
  • @DavidWallace Is there an algorithm for modular exponentiation with decimal exponents? – royhowie Nov 13 '14 at 04:33
  • I don't know of one. I suspect that there is no good answer here, because the inherent inaccuracy of the `double` datatype for expressing decimal numbers gets amplified by the exponentiation; and then when you apply the mod at the end, all you get left with are the errors. If I have time later, I will write an answer explaining in more detail why what OP is asking for is mathematically impossible. – Dawood ibn Kareem Nov 13 '14 at 04:42
  • @DavidWallace In case you don't find time to write an answer, would you happen to have any resources that would explain why it's mathematically impossible? I'd like to know more. – royhowie Nov 13 '14 at 06:16
  • Well, it's because when you write `double b = 10002.3443;`, the `double` that you get isn't exactly `10002.3443`. The error is minuscule, and irrelevant for most purposes. But when you do `10^` of it, the error becomes enormous; although since we're looking at a 10003-digit number, it's enormous in an insignificant way. But because it's much bigger than `10000007`, when you do `% 10000007`, the result is completely swamped by the error. This is the case no matter how you calculate it. – Dawood ibn Kareem Nov 13 '14 at 06:45
  • I would certainly love to hear an answer from someone ...@DavidWallace – Ira Singh Nov 13 '14 at 07:25