4

У меня есть следующий, метод работы в Java:оператор Модульное дает неожиданный вывод в 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 

отлично работает п могучим, но я попробовал это по-другому в первый раз:

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

Однако, для log(729) % log(3), кажется, возвращает 1.0986122886681093, а результат log(729)/log(3) is 6.

Любой, кто может сказать мне, что приводит к тому, что оператор modulo все еще дает 1.09 остаток здесь?

ответ

7

Любой, кто может сказать мне, что приводит к тому, что оператор modulo все еще дает 1.09 остатка здесь?

Нормальные неточности в плавающей запятой, в основном. Значения, которые вы используете, не являются точно log (729) и log (3). Если вы посмотрите на log(3) и log(729) % log(3) вы увидите, что они почти точно так же:

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); 
    } 
} 

Выход:

6.591673732008658 
1.0986122886681098 
1.0986122886681093 

Другими словами, log(729) эффективно log(3) * 5.9999999999999 (или нечто подобное). Вероятно, вы захотите добавить некоторую терпимость к своему тесту, в основном, и вернуть, остается ли остаток очень близко к 0 или очень близко к log(z).

В качестве альтернативы, используйте log и деление отработать «примерно», что власть должна быть, то Math.pow, чтобы проверить точное значение:

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

Здесь вы должны быть в порядке с точки зрения точечных неточностей плавающих, пока цифры становятся «довольно большими». Вы можете использовать BigInteger, если вы хотите справиться с очень больших чисел точно.

+0

Все, что мне нужно было знать, спасибо большое! –

2
Math.log(729) = 6.591673732008658 
Math.log(3) = 1.0986122886681098 

d= 1.0986122886681093 

Если вы заметили, d (1.0986122886681093) немного меньше (последняя цифра), чем Math.log(3)-(1.0986122886681098) значение добавить, кажется, работает хорошо. Вероятно, вам не хватает понимания точности данных двойного типа. Номера с плавающей запятой имеют некоторые неточности для значений высокой точности из-за их фактического представления.