Si vous envisagez d'utiliser la virgule flottante pour vous aider avec l'arithmétique entière, vous devez être prudent.
J'essaie généralement d'éviter les calculs de FP autant que possible.
Les opérations en virgule flottante ne sont pas exactes. Vous ne pouvez jamais savoir avec certitude ce qui vaudra (int)(Math.log(65536)/Math.log(2))
. Par exemple, Math.ceil(Math.log(1<<29) / Math.log(2))
est 30 sur mon PC où mathématiquement il devrait être exactement 29. Je n'ai pas trouvé de valeur pour x où (int)(Math.log(x)/Math.log(2))
échoue (simplement parce qu'il n'y a que 32 valeurs "dangereuses"), mais cela ne signifie pas que cela fonctionnera le de la même manière sur n'importe quel PC.
L'astuce habituelle ici est d'utiliser "epsilon" lors de l'arrondi. Comme (int)(Math.log(x)/Math.log(2)+1e-10)
ne devrait jamais échouer. Le choix de cet "epsilon" n'est pas une tâche anodine.
Plus de démonstration, en utilisant une tâche plus générale - essayer de mettre en œuvre int log(int x, int base)
:
Le code de test:
static int pow(int base, int power) {
int result = 1;
for (int i = 0; i < power; i++)
result *= base;
return result;
}
private static void test(int base, int pow) {
int x = pow(base, pow);
if (pow != log(x, base))
System.out.println(String.format("error at %d^%d", base, pow));
if(pow!=0 && (pow-1) != log(x-1, base))
System.out.println(String.format("error at %d^%d-1", base, pow));
}
public static void main(String[] args) {
for (int base = 2; base < 500; base++) {
int maxPow = (int) (Math.log(Integer.MAX_VALUE) / Math.log(base));
for (int pow = 0; pow <= maxPow; pow++) {
test(base, pow);
}
}
}
Si nous utilisons l'implémentation la plus simple du logarithme,
static int log(int x, int base)
{
return (int) (Math.log(x) / Math.log(base));
}
ceci imprime:
error at 3^5
error at 3^10
error at 3^13
error at 3^15
error at 3^17
error at 9^5
error at 10^3
error at 10^6
error at 10^9
error at 11^7
error at 12^7
...
Pour me débarrasser complètement des erreurs, j'ai dû ajouter epsilon qui se situe entre 1e-11 et 1e-14. Auriez-vous pu le dire avant de tester? Je ne pourrais certainement pas.