Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/388.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么log(1000)/log(10)不是';是否与log10(1000)相同?_Java_C_Math_Logarithm - Fatal编程技术网

Java 为什么log(1000)/log(10)不是';是否与log10(1000)相同?

Java 为什么log(1000)/log(10)不是';是否与log10(1000)相同?,java,c,math,logarithm,Java,C,Math,Logarithm,今天,我遇到了一个很奇怪的问题。我需要计算一个数字的字符串长度,所以我提出了这个解决方案 // say the number is 1000 (int)(log(1000)/log(10)) + 1 这是基于数学公式 log10x=lognx/logn10(已解释) 但我发现,在C中 (int)(log(1000)/log(10)) + 1 不等于 (int) log10(1000) + 1 但应该是这样 我甚至在Java中用这段代码做了同样的尝试 (int) (Math.log(1000

今天,我遇到了一个很奇怪的问题。我需要计算一个数字的字符串长度,所以我提出了这个解决方案

// say the number is 1000
(int)(log(1000)/log(10)) + 1
这是基于数学公式

log
10
x=log
n
x/log
n
10
(已解释)

但我发现,在C中

(int)(log(1000)/log(10)) + 1
不等于

(int) log10(1000) + 1
但应该是这样

我甚至在Java中用这段代码做了同样的尝试

(int) (Math.log(1000) / Math.log(10)) + 1
(int) Math.log10(1000) + 1
for (int i = 10; i < 10000000; i *= 10) {
   System.out.println(((int) (Math.log10(i)) + 1) + 
                " " + ((int) (Math.log(i) / Math.log(10)) + 1));
}
但它的行为方式同样错误

故事还在继续。执行此代码之后

(int) (Math.log(1000) / Math.log(10)) + 1
(int) Math.log10(1000) + 1
for (int i = 10; i < 10000000; i *= 10) {
   System.out.println(((int) (Math.log10(i)) + 1) + 
                " " + ((int) (Math.log(i) / Math.log(10)) + 1));
}
因此,缺陷似乎每1000的倍数出现一次

我向我的C老师展示了这个,他说这可能是由于日志分割过程中的一些类型转换错误造成的,但他不知道为什么

所以我的问题是

  • 为什么
    (int)(Math.log(1000)/Math.log(10))+1
    不等于
    (int)Math.log10(1000)+1
    
    ,而根据数学计算,它应该是。
  • 为什么只有1000的倍数是错误的?
编辑:这不是舍入错误,因为

Math.floor(Math.log10(i)) + 1
Math.floor(Math.log(i) / Math.log(10)) + 1
产生相同、错误的输出

2 2
3 3
4 3
5 5
6 6
7 6
edit2:我必须向下取整,因为我想知道位数

log10(999) + 1 = 3.9995654882259823
log10(1000) + 1 =  4.0

如果我只是四舍五入,我会得到相同的结果(4),这对于999来说是错误的,因为它有3个数字。

更新:这是由于精度和四舍五入错误造成的。

如果你想将结果作为一个整数,你可能应该四舍五入,而不仅仅是切掉点后的部分


您可能会得到类似6.999999的值,并将其四舍五入为6。

使用(int)转换,您将删除必要的小数部分。尝试将它们打印为双倍而不强制转换(为什么要强制转换?),您会很好。

您提供了代码片段

for (int i = 10; i < 10000000; i *= 10) {
   System.out.println(((int) (Math.log10(i)) + 1) + 
                " " + ((int) (Math.log(i) / Math.log(10)) + 1));
}
这立刻回答了你的问题。正如特利夫已经指出的那样,强制转换将小数切掉,而不是适当地四舍五入


编辑:您已将问题更新为使用
floor()
,但像铸造
floor()
一样,将向下取整,因此删除小数

打印中间结果,即log(1000)、log(10)、log(1000)/log(10)和log10(1000)。这应该比猜测给出更好的提示。

这是由于精度和舍入问题
Math.log(1000)/Math.log(10)
并不完全等于3

如果你需要精确的精度,不要使用浮点运算,一般情况下不要使用对数。浮点数本质上是模糊的。要获得精确的结果,请使用整数算术

我真的建议你一般不要走这条路,但听起来你是用整数的对数来确定某个数量级。如果是这样的话,那么
(int)(Math.log(x+0.5)/Math.log(10))
会更稳定,但是要知道
double
的精度只有53位,所以第15个double中的大约10位不再能准确地表示整数,而这个技巧在那时就不起作用了。

日志操作是一个简单的过程。计算机评估结果的最佳方法是使用近似于所需操作的方法。结果的准确性取决于计算机使用的算法(这可能是FPU中的微码)。在英特尔FPU上,有一些设置会影响各种超越函数(trig函数也是超越函数)的精度,FPU规范将详细说明所用各种算法的精度级别


因此,除了上述舍入误差外,还存在精度问题,因为计算的对数(x)可能不等于实际对数(x)。

向分子添加一个非常小的值,以绕过Skizz指出的精度问题

// say the number is 1000
(int)((log(1000)+1E-14)/log(10)) + 1
1E-14应足以将精度推回到轨道上

更改了1E-15的小值,这将对某些输入给出不正确的结果


我用1E-14测试了
无符号long-long
s的随机样本,我所有的数字都通过了。

这没关系,因为它使用公式从一个基数转换到另一个基数,实际上无法进行舍入,因为当你有log10(100)和log10(99)时,第二个基数略低于2,所以当我进行舍入时,它会给我和100一样的结果,这是错误的。。我可以使用floor()函数进行四舍五入,尽管这些函数的未经取整的输出是:log10(1000)=4.0 log(1000)/log(10)=3.9999999996使用
floor
比使用
round
更合理的做法是什么?尝试log10(999)+1,您会得到3.99956654882259823,因为我需要位数。如果我四舍五入,我得到4,这与log10(1000)+1相同,但它是一位数长。最好使用Integer.toString(n).length()来获得长度。@starblue:是的,但我的老师想用数学的方法实现它。你有一个编程老师不懂有限精度。糟糕的大学。如果我不放弃,并执行这个数学。log10(9)+1,它会得到1.954,这是1,因为2代表数学。log10(10)+1gs:呃,不,4有一个精确的浮点表示。该错误是由于除法之前的值不准确造成的。为什么将其标记为正确答案?在你的问题中,你发现了如何区分log10(999)和log10(1000)了吗?1E-15太小了,不适用于“1000”。。。最好按照上面的建议使用0.5。你是对的。。。但0.5表示您正在尝试解决取整问题。1E-14(带有IEEE 64位双精度)适用于1000,至少适用于我测试的0和2^64-1之间的少数值。