Java double - 特定小数位后只有零
Java double - Only zeros after certain decimal place
我写了一个程序,它可以暴力破解带有很多小数位的平方根。这工作正常,但只能达到小数点后第 50 位。例如,当使用 12 作为该方法的输入时,小数点后第 50 位后,仅出现零。我很确定这不是预期的输出。
我不认为这是一个精度问题,因为我已经在使用 BigDecimal
s 进行计算了。这是我当前的代码:
static String solve(double num, int decimalPlaces) {
BigDecimal toAdd = new BigDecimal("1.0");
BigDecimal currentNumber = new BigDecimal("0.0");
for(int i = 0; i <= decimalPlaces; i++) {
currentNumber = currentNumber.setScale(i);
System.out.print(currentNumber.toPlainString() + " >> " + i + "\r");
while(Math.pow((currentNumber.add(toAdd).doubleValue()), 2) <= num) {
currentNumber = currentNumber.add(toAdd);
}
toAdd = toAdd.divide(BigDecimal.TEN);
}
return currentNumber.toPlainString();
}
当前输出(当num = 12
和decimalPlaces = 80
):
3.46410161513775460839781317190499976277351379394531250000000000000000000000000000
您知道为什么会这样以及可能的解决方案吗?
tl;博士
- 如果您想要宽 range/precision 的准确结果,请消除对浮点类型
double
/Double
和 float
/Float
的任何使用。
- 仅使用
BigDecimal
个对象。
仅使用 BigDecimal
,不使用 double
当你涉及一个 double
原始值或一个 Double
对象时,你 loose accuracy due to floating-point 数学。
您的方法将 double
作为其名为 num
的第一个参数。如果您想要准确性和 range/precision,请改用 BigDecimal
。
static String solve( BigDecimal num, int decimalPlaces ) { … }
以这种方式调用该方法。请注意,我们将十二作为字符串文字而不是数字文字传递。
String result = Whatever.solve ( new BigDecimal( "12" ) , 80 ) ;
您不能对对象使用比较器语法,例如 <=
。您的行 while(Math.pow((currentNumber.add(toAdd).doubleValue()), 2) <= num)
应该改为调用方法 BigDecimal::pow
.
小问题…您的行 System.out.print( currentNumber.toPlainString()
应该是 System.out.println( …
,调用 println
而不是 print
。
这可能与您寻找的代码很接近。我不是数学高手所以我不能保证逻辑。
static String solve ( BigDecimal num , int decimalPlaces )
{
BigDecimal toAdd = new BigDecimal( "1.0" );
BigDecimal currentNumber = new BigDecimal( "0.0" );
for ( int i = 0 ; i <= decimalPlaces ; i++ )
{
currentNumber = currentNumber.setScale( i );
System.out.println( currentNumber.toPlainString() + " >> " + i + "\r" );
while ( currentNumber.add( toAdd ).pow( 2 ).compareTo( num ) <= 0 )
{
currentNumber = currentNumber.add( toAdd );
}
toAdd = toAdd.divide( BigDecimal.TEN );
}
return currentNumber.toPlainString();
}
看到这个code run live on IdeOne.com。
0 >> 0
3.0 >> 1
3.40 >> 2
3.460 >> 3
3.4640 >> 4
3.46410 >> 5
3.464100 >> 6
3.4641010 >> 7
3.46410160 >> 8
3.464101610 >> 9
3.4641016150 >> 10
3.46410161510 >> 11
3.464101615130 >> 12
3.4641016151370 >> 13
3.46410161513770 >> 14
3.464101615137750 >> 15
3.4641016151377540 >> 16
3.46410161513775450 >> 17
3.464101615137754580 >> 18
3.4641016151377545870 >> 19
3.46410161513775458700 >> 20
3.464101615137754587050 >> 21
3.4641016151377545870540 >> 22
3.46410161513775458705480 >> 23
3.464101615137754587054890 >> 24
3.4641016151377545870548920 >> 25
3.46410161513775458705489260 >> 26
3.464101615137754587054892680 >> 27
3.4641016151377545870548926830 >> 28
3.46410161513775458705489268300 >> 29
3.464101615137754587054892683010 >> 30
3.4641016151377545870548926830110 >> 31
3.46410161513775458705489268301170 >> 32
3.464101615137754587054892683011740 >> 33
3.4641016151377545870548926830117440 >> 34
3.46410161513775458705489268301174470 >> 35
3.464101615137754587054892683011744730 >> 36
3.4641016151377545870548926830117447330 >> 37
3.46410161513775458705489268301174473380 >> 38
3.464101615137754587054892683011744733880 >> 39
3.4641016151377545870548926830117447338850 >> 40
3.46410161513775458705489268301174473388560 >> 41
3.464101615137754587054892683011744733885610 >> 42
3.4641016151377545870548926830117447338856100 >> 43
3.46410161513775458705489268301174473388561050 >> 44
3.464101615137754587054892683011744733885610500 >> 45
3.4641016151377545870548926830117447338856105070 >> 46
3.46410161513775458705489268301174473388561050760 >> 47
3.464101615137754587054892683011744733885610507620 >> 48
3.4641016151377545870548926830117447338856105076200 >> 49
3.46410161513775458705489268301174473388561050762070 >> 50
3.464101615137754587054892683011744733885610507620760 >> 51
3.4641016151377545870548926830117447338856105076207610 >> 52
3.46410161513775458705489268301174473388561050762076120 >> 53
3.464101615137754587054892683011744733885610507620761250 >> 54
3.4641016151377545870548926830117447338856105076207612560 >> 55
3.46410161513775458705489268301174473388561050762076125610 >> 56
3.464101615137754587054892683011744733885610507620761256110 >> 57
3.4641016151377545870548926830117447338856105076207612561110 >> 58
3.46410161513775458705489268301174473388561050762076125611160 >> 59
3.464101615137754587054892683011744733885610507620761256111610 >> 60
3.4641016151377545870548926830117447338856105076207612561116130 >> 61
3.46410161513775458705489268301174473388561050762076125611161390 >> 62
3.464101615137754587054892683011744733885610507620761256111613950 >> 63
3.4641016151377545870548926830117447338856105076207612561116139580 >> 64
3.46410161513775458705489268301174473388561050762076125611161395890 >> 65
3.464101615137754587054892683011744733885610507620761256111613958900 >> 66
3.4641016151377545870548926830117447338856105076207612561116139589030 >> 67
3.46410161513775458705489268301174473388561050762076125611161395890380 >> 68
3.464101615137754587054892683011744733885610507620761256111613958903860 >> 69
3.4641016151377545870548926830117447338856105076207612561116139589038660 >> 70
3.46410161513775458705489268301174473388561050762076125611161395890386600 >> 71
3.464101615137754587054892683011744733885610507620761256111613958903866030 >> 72
3.4641016151377545870548926830117447338856105076207612561116139589038660330 >> 73
3.46410161513775458705489268301174473388561050762076125611161395890386603380 >> 74
3.464101615137754587054892683011744733885610507620761256111613958903866033810 >> 75
3.4641016151377545870548926830117447338856105076207612561116139589038660338170 >> 76
3.46410161513775458705489268301174473388561050762076125611161395890386603381760 >> 77
3.464101615137754587054892683011744733885610507620761256111613958903866033817600 >> 78
3.4641016151377545870548926830117447338856105076207612561116139589038660338176000 >> 79
3.46410161513775458705489268301174473388561050762076125611161395890386603381760000 >> 80
result: 3.46410161513775458705489268301174473388561050762076125611161395890386603381760007
您在 Math.pow((currentNumber.add(toAdd).doubleValue()), 2)
中将您的大小数转换为双精度,而您在这里失去了精度。只需在 BigDecimal 本身上使用方法 pow
即可产生能量。
这是更正后的代码,似乎对我有用:
static String solve(double num, int decimalPlaces) {
BigDecimal toAdd = new BigDecimal("1.0");
BigDecimal currentNumber = new BigDecimal("0.0");
BigDecimal numBD = BigDecimal.valueOf(num);
for (int i = 0; i <= decimalPlaces; i++) {
currentNumber = currentNumber.setScale(i);
System.out.print(currentNumber.toPlainString() + " >> " + i + "\r");
while (currentNumber.add(toAdd).pow(2).compareTo(numBD) <= 0) {
currentNumber = currentNumber.add(toAdd);
}
toAdd = toAdd.divide(BigDecimal.TEN);
}
return currentNumber.toPlainString();
}
作为一个额外的好处,这段代码实际上更简单一些。
我写了一个程序,它可以暴力破解带有很多小数位的平方根。这工作正常,但只能达到小数点后第 50 位。例如,当使用 12 作为该方法的输入时,小数点后第 50 位后,仅出现零。我很确定这不是预期的输出。
我不认为这是一个精度问题,因为我已经在使用 BigDecimal
s 进行计算了。这是我当前的代码:
static String solve(double num, int decimalPlaces) {
BigDecimal toAdd = new BigDecimal("1.0");
BigDecimal currentNumber = new BigDecimal("0.0");
for(int i = 0; i <= decimalPlaces; i++) {
currentNumber = currentNumber.setScale(i);
System.out.print(currentNumber.toPlainString() + " >> " + i + "\r");
while(Math.pow((currentNumber.add(toAdd).doubleValue()), 2) <= num) {
currentNumber = currentNumber.add(toAdd);
}
toAdd = toAdd.divide(BigDecimal.TEN);
}
return currentNumber.toPlainString();
}
当前输出(当num = 12
和decimalPlaces = 80
):
3.46410161513775460839781317190499976277351379394531250000000000000000000000000000
您知道为什么会这样以及可能的解决方案吗?
tl;博士
- 如果您想要宽 range/precision 的准确结果,请消除对浮点类型
double
/Double
和float
/Float
的任何使用。 - 仅使用
BigDecimal
个对象。
仅使用 BigDecimal
,不使用 double
当你涉及一个 double
原始值或一个 Double
对象时,你 loose accuracy due to floating-point 数学。
您的方法将 double
作为其名为 num
的第一个参数。如果您想要准确性和 range/precision,请改用 BigDecimal
。
static String solve( BigDecimal num, int decimalPlaces ) { … }
以这种方式调用该方法。请注意,我们将十二作为字符串文字而不是数字文字传递。
String result = Whatever.solve ( new BigDecimal( "12" ) , 80 ) ;
您不能对对象使用比较器语法,例如 <=
。您的行 while(Math.pow((currentNumber.add(toAdd).doubleValue()), 2) <= num)
应该改为调用方法 BigDecimal::pow
.
小问题…您的行 System.out.print( currentNumber.toPlainString()
应该是 System.out.println( …
,调用 println
而不是 print
。
这可能与您寻找的代码很接近。我不是数学高手所以我不能保证逻辑。
static String solve ( BigDecimal num , int decimalPlaces )
{
BigDecimal toAdd = new BigDecimal( "1.0" );
BigDecimal currentNumber = new BigDecimal( "0.0" );
for ( int i = 0 ; i <= decimalPlaces ; i++ )
{
currentNumber = currentNumber.setScale( i );
System.out.println( currentNumber.toPlainString() + " >> " + i + "\r" );
while ( currentNumber.add( toAdd ).pow( 2 ).compareTo( num ) <= 0 )
{
currentNumber = currentNumber.add( toAdd );
}
toAdd = toAdd.divide( BigDecimal.TEN );
}
return currentNumber.toPlainString();
}
看到这个code run live on IdeOne.com。
0 >> 0
3.0 >> 1
3.40 >> 2
3.460 >> 3
3.4640 >> 4
3.46410 >> 5
3.464100 >> 6
3.4641010 >> 7
3.46410160 >> 8
3.464101610 >> 9
3.4641016150 >> 10
3.46410161510 >> 11
3.464101615130 >> 12
3.4641016151370 >> 13
3.46410161513770 >> 14
3.464101615137750 >> 15
3.4641016151377540 >> 16
3.46410161513775450 >> 17
3.464101615137754580 >> 18
3.4641016151377545870 >> 19
3.46410161513775458700 >> 20
3.464101615137754587050 >> 21
3.4641016151377545870540 >> 22
3.46410161513775458705480 >> 23
3.464101615137754587054890 >> 24
3.4641016151377545870548920 >> 25
3.46410161513775458705489260 >> 26
3.464101615137754587054892680 >> 27
3.4641016151377545870548926830 >> 28
3.46410161513775458705489268300 >> 29
3.464101615137754587054892683010 >> 30
3.4641016151377545870548926830110 >> 31
3.46410161513775458705489268301170 >> 32
3.464101615137754587054892683011740 >> 33
3.4641016151377545870548926830117440 >> 34
3.46410161513775458705489268301174470 >> 35
3.464101615137754587054892683011744730 >> 36
3.4641016151377545870548926830117447330 >> 37
3.46410161513775458705489268301174473380 >> 38
3.464101615137754587054892683011744733880 >> 39
3.4641016151377545870548926830117447338850 >> 40
3.46410161513775458705489268301174473388560 >> 41
3.464101615137754587054892683011744733885610 >> 42
3.4641016151377545870548926830117447338856100 >> 43
3.46410161513775458705489268301174473388561050 >> 44
3.464101615137754587054892683011744733885610500 >> 45
3.4641016151377545870548926830117447338856105070 >> 46
3.46410161513775458705489268301174473388561050760 >> 47
3.464101615137754587054892683011744733885610507620 >> 48
3.4641016151377545870548926830117447338856105076200 >> 49
3.46410161513775458705489268301174473388561050762070 >> 50
3.464101615137754587054892683011744733885610507620760 >> 51
3.4641016151377545870548926830117447338856105076207610 >> 52
3.46410161513775458705489268301174473388561050762076120 >> 53
3.464101615137754587054892683011744733885610507620761250 >> 54
3.4641016151377545870548926830117447338856105076207612560 >> 55
3.46410161513775458705489268301174473388561050762076125610 >> 56
3.464101615137754587054892683011744733885610507620761256110 >> 57
3.4641016151377545870548926830117447338856105076207612561110 >> 58
3.46410161513775458705489268301174473388561050762076125611160 >> 59
3.464101615137754587054892683011744733885610507620761256111610 >> 60
3.4641016151377545870548926830117447338856105076207612561116130 >> 61
3.46410161513775458705489268301174473388561050762076125611161390 >> 62
3.464101615137754587054892683011744733885610507620761256111613950 >> 63
3.4641016151377545870548926830117447338856105076207612561116139580 >> 64
3.46410161513775458705489268301174473388561050762076125611161395890 >> 65
3.464101615137754587054892683011744733885610507620761256111613958900 >> 66
3.4641016151377545870548926830117447338856105076207612561116139589030 >> 67
3.46410161513775458705489268301174473388561050762076125611161395890380 >> 68
3.464101615137754587054892683011744733885610507620761256111613958903860 >> 69
3.4641016151377545870548926830117447338856105076207612561116139589038660 >> 70
3.46410161513775458705489268301174473388561050762076125611161395890386600 >> 71
3.464101615137754587054892683011744733885610507620761256111613958903866030 >> 72
3.4641016151377545870548926830117447338856105076207612561116139589038660330 >> 73
3.46410161513775458705489268301174473388561050762076125611161395890386603380 >> 74
3.464101615137754587054892683011744733885610507620761256111613958903866033810 >> 75
3.4641016151377545870548926830117447338856105076207612561116139589038660338170 >> 76
3.46410161513775458705489268301174473388561050762076125611161395890386603381760 >> 77
3.464101615137754587054892683011744733885610507620761256111613958903866033817600 >> 78
3.4641016151377545870548926830117447338856105076207612561116139589038660338176000 >> 79
3.46410161513775458705489268301174473388561050762076125611161395890386603381760000 >> 80
result: 3.46410161513775458705489268301174473388561050762076125611161395890386603381760007
您在 Math.pow((currentNumber.add(toAdd).doubleValue()), 2)
中将您的大小数转换为双精度,而您在这里失去了精度。只需在 BigDecimal 本身上使用方法 pow
即可产生能量。
这是更正后的代码,似乎对我有用:
static String solve(double num, int decimalPlaces) {
BigDecimal toAdd = new BigDecimal("1.0");
BigDecimal currentNumber = new BigDecimal("0.0");
BigDecimal numBD = BigDecimal.valueOf(num);
for (int i = 0; i <= decimalPlaces; i++) {
currentNumber = currentNumber.setScale(i);
System.out.print(currentNumber.toPlainString() + " >> " + i + "\r");
while (currentNumber.add(toAdd).pow(2).compareTo(numBD) <= 0) {
currentNumber = currentNumber.add(toAdd);
}
toAdd = toAdd.divide(BigDecimal.TEN);
}
return currentNumber.toPlainString();
}
作为一个额外的好处,这段代码实际上更简单一些。