Modulo operator gives unexpected output in Java

I have the following working method in Java:

/** * Determines if n is a power of z * * @param z the number that n may be a power of * @param n the number that may be a power of z * @return true if n is a power of z */ public boolean isPowerOf(int z, int n) { double output = Math.log(n) / Math.log(z); if(output % 1 > 0) { return false; } else { return true; } } isPowerOf(3, 729); //returns true, because 3^6 = 729 

Works fine n mighty, but I tried it differently the first time:

 public boolean isPowerOf(int z, int n) { double output = Math.log(n) % Math.log(z); if(output != 0) { return false; } else { return true; } } 

However, for log(729) % log(3) , it seems that 1.0986122886681093 returned, and the result is log(729) / log(3) is 6 .

Can anyone tell me why the modulo operator still gives 1.09 remainder here?

+4
source share
2 answers

Can anyone tell me what makes the modulo operator still give 1.09 remainder here?

Common floating point inaccuracies, mostly. The values ​​you use do not exactly match log (729) and log (3). If you look at log(3) and log(729) % log(3) , you will see that they are almost exactly the same:

 public class Test { public static void main(String[] args) { double x = Math.log(729); double y = Math.log(3); System.out.println(x); System.out.println(y); System.out.println(x % y); } } 

Output:

 6.591673732008658 1.0986122886681098 1.0986122886681093 

In other words, log(729) effectively log(3) * 5.9999999999999 (or something similar). You will probably want to add tolerance to your test, basically, and return if the remainder is very close to 0 or very close to log(z) .

Alternatively, use log and division to work out “roughly” what should be valid, and then Math.pow to check the exact value:

 int power = (int) (Math.log(n) / Math.log(z) + 0.5); return n == Math.pow(z, power); 

Here you should be fine in terms of floating point inaccuracies until the numbers get “pretty big”. You can use BigInteger if you want to handle very large numbers accurately.

+7
source
 Math.log(729) = 6.591673732008658 Math.log(3) = 1.0986122886681098 d= 1.0986122886681093 

If you notice d (1.0986122886681093) slightly smaller (last digit) than the value of Math.log(3)-(1.0986122886681098) , add it, it seems to work fine. You probably lack an understanding of the accuracy of double-type data. Floating-point numbers have some inaccuracies for high-precision values ​​due to their actual representation.

+2
source

Source: https://habr.com/ru/post/1441562/


All Articles