问题描述
我只想简单地将一个具有小数位数的双精度数字转换为4个小数位数而不四舍五入的函数。 我的这段代码运行正常,但是找到了一个随机实例,将.0转换为.99 这是一些示例输出
4.12897456 ->4.1289
4.5 ->4.5
4.5231->4.5231
5.53->5.53
5.52->5.199 (Wrong conversion,I want it to be 5.52)
private static double get4Donly(double val){
double converted = ((long)(val * 1e4)) / 1e4;
return converted
}
编辑:这种转换被调用了数千次,所以请提出一种我不必一直创建新字符串的方法。
解决方法
您可以使用DecimalFormat
import java.text.DecimalFormat;
import java.math.RoundingMode;
import java.util.Arrays;
public class MyClass {
public static void main(String args[]) {
DecimalFormat df = new DecimalFormat("#.####");
df.setRoundingMode(RoundingMode.DOWN);
for (Number n : Arrays.asList(4.12897456,4.5,4.5231,5.53,5.52)) {
Double d = n.doubleValue();
System.out.println(df.format(d));
}
}
}
RoundingMode.DOWN
舍入为零,new DecimalFormat("#.####")
创建一个DecimalFormat
实例,该实例将数字格式化为最多4个小数位。将两者放在一起,上面的代码将产生以下输出,我相信这符合您的期望:
4.1289
4.5
4.5231
5.53
5.52
,我建议通过将double转换为String来使用.substring()
方法。由于您不需要四舍五入,因此更容易理解和实现。
此外,它是所有其他方法中最简单的方法,例如使用DecimalFormat
在这种情况下,您可以这样做:
private static double get4Donly(double val){
String num = String.valueOf(val);
return Double.parseDouble(num.substring(0,6));
}
但是,如果结果的长度小于6个字符,则可以执行以下操作:
private static double get4Donly(double val){
String num = String.valueOf(val);
if(num.length()>6) {
return Double.parseDouble(num.substring(0,6));
}else {
return val;
}
}
,
双打并不像您认为的那样起作用。
它们以二进制形式而不是十进制形式存储。就像'1除以3'不能用十进制双精度表示(0.3333333333
是不够的,它是无限的3s,所以不能表示,因此会产生舍入误差),但是'1除以5'是可以表示的很好,有些数字是可表示的,并且在以double
类型存储时,这些数字最终会四舍五入,但至关重要的是,十进制看上去完全可以舍入的东西可能无法用二进制进行舍入。
鉴于它们不匹配,您的想法是“嗯,我将乘以4,将其变为长整数,然后再转换为双精度数,然后除以1000”不会让这些数字消失通过毫不留情。这不是您四舍五入的方法,因为除了使用双打已经开始造成的损失之外,您还引入了其他损失。
您有3种解决方案:
只需正确打印
双精度数不能认为是“小数点后有4位数字”,因为双精度数不是十进制数。
因此,说这句话甚至都没有道理:请将此双数取整至最多4个小数位数。
那是至关重要的认识。一旦您了解到您会顺利进行的:)
您可以做的是“请取这双并用小数点后的不超过4位数字打印出来。”
String out = String.format("%.4f",5.52);
或者您可以使用System.printf(XXX)
的缩写System.print(String.format(XXX))
。
这可能就是您想要的
忘记完全翻倍
对于某些领域,最好放弃双打并改用多头或整数。例如,如果您要进行财务业务,最好将每种货币的原子单位长期存储,而放弃双倍。因此,以美元计,可以长期存储美分。对于欧元,相同。对于比特币,请存储satoshis。编写自定义渲染,以适合该货币的形式渲染回去:
long value = 450; // $4.50
String formatCurrency(long cents) {
return String.format("%s%s%d.%02d",cents < 0 ? "-" : " ","$",Math.abs(cents) / 100,Math.abs(cents) % 100);
}
使用BigDecimal
这通常比麻烦多得多,但是它以十进制存储每个数字-它代表十进制表示法可以做到的所有事情(而且它也不能代表其他任何东西-BigDecimal中不可能用1除以3)。