Java 确保十进制数的字符串长度始终为n个字符
我需要确保我所有的十进制数总是最多15个字符(包括点),同时保持尽可能高的精度。因此,它最多必须是15个字符,包括“.”表示科学记数法的“E”和“-” 我的想法是对大数字使用科学记数法,对小数字使用舍入法 例如,对于1234567891234567.123456789,我会使用科学记数法,但是对于0.123456789123456789,我会将其四舍五入 我寻找了可以为我实现这一点的java库,但找不到任何可以让我指定表示的字符总数的库 感谢您的建议和指点 编辑:更多想法-使用24000E-18可以毫无损失地表示0.000000000000024等数字。例如,0.123456789123424必须遭受一些损失,这当然会使编写任何类型的简单分支算法变得更加困难 EDIT2:我们用于传输数据的格式是字母数字格式,并且将数据限制为总共15个字符。我必须编写满足格式要求的代码,以便在不触发格式错误的情况下传输数据,但同时仍将最大精度保持在限制范围内 EDIT3:我用它来测试我的功能,但到目前为止,在很多情况下,一切都失败了:Java 确保十进制数的字符串长度始终为n个字符,java,string-formatting,number-formatting,decimalformat,Java,String Formatting,Number Formatting,Decimalformat,我需要确保我所有的十进制数总是最多15个字符(包括点),同时保持尽可能高的精度。因此,它最多必须是15个字符,包括“.”表示科学记数法的“E”和“-” 我的想法是对大数字使用科学记数法,对小数字使用舍入法 例如,对于1234567891234567.123456789,我会使用科学记数法,但是对于0.123456789123456789,我会将其四舍五入 我寻找了可以为我实现这一点的java库,但找不到任何可以让我指定表示的字符总数的库 感谢您的建议和指点 编辑:更多想法-使用24000E-18
Random rnd = new Random();
double n = 100000 + rnd.nextDouble() * 900000;
String res;
double rangeMin = -123456789123456D;
double rangeMax = 123456789123456D;
String val;
for (int i=1;i<=1000;i++) {
n = rangeMin + (rangeMax - rangeMin) * rnd.nextDouble();
val = Double.toString(n);
res = shorteningFunction(val);
System.out.println(val + " " + val.length() + " " + res + " " + res.length());
}
Random rnd=new Random();
双n=100000+rnd.nextDouble()*900000;
字符串res;
双量程最小值=-123456789123456D;
双量程最大值=123456789123456D;
字符串val;
对于(inti=1;i我不希望发布不起作用的代码,所以我已经删除了混乱
这就是伪代码中的想法:
把它变成一根绳子
检查长度
循环:
- 如果长度太长:
- 除去预感
- 把它变成一根绳子
- 检查长度
返回
可以使用BigDecimal
,对于整数部分biginger
/**
* @param num number representation.
* @param max the maximal length the result should have.
* @return
*/
public static String truncateNumber(String num, int max) {
num = num.replaceFirst("\\.0*$", "");
BigDecimal x = new BigDecimal(num);
// Large numbers - integral part
String bigI = x.toBigInteger().toString();
if (bigI.length() > max) {
int expon10 = bigI.length() - max - 1; // - 1 for E
// Digits after E:
if (expon10 == 0) {
++expon10;
} else {
for (int p = expon10; p > 0; ++p) {
++expon10;
p /= 10;
}
}
x = x.movePointLeft(expon10);
String plain = x.toPlainString().substring(0, max - 1 - expon10);
return plain + "E" + expon10;
}
// Tiny numbers - 0.000 (as E-1 already requires 3 positions)
String reprP = x.toPlainString();
if (reprP.startsWith("-0.00")) {
return truncateNumber(num.substring(1), max - 1);
} else if (reprP.startsWith("0.00")) {
String reprE = x.toEngineeringString(); // Does most work.
int epos = reprE.indexOf('E');
String mantissa = reprE.substring(0, epos);
String exp = reprE.substring(epos);
return mantissa.substring(0, Math.min(epos, max - exp.length())) + exp;
}
// Normal range - assumed in format 123.456, integral part in range
String simple = x.toPlainString();
if (simple.length() > max) {
simple = simple.substring(0, max).replaceFirst("\\.0*$", "");
}
return simple;
}
这可能会写得更好,子字符串以\.0*
结尾,尤其是toPlainString之类的重复使用。此外,过小的max
也会有害
是否用科学/工程符号给出num
也是开放的。您应该使用BigDecimal
,然后设置您想要的精度。@TimBiegeleisen精度似乎不处理字符,而是处理数字。也许我缺少它,但我不知道如何限制字符总数?可以吗你介意重新开始我的问题吗?这似乎不能回答问题?一个数字不是一个字符吗?@TimBiegeleisen确实是,但它不包括点字符或“E”当使用科学记数法时。有这个要求是没有意义的。这难道不是意味着不是所有的数字都会以相同的精度存储吗?你真的想要吗?回答得很好,但是-1234567889123456
会导致-1.2345678912346E+14
(长度20).这确实是一个很好的起点,谢谢!0.00542299没有任何变化(16个字符).我在刚刚编辑的内容中提供了一个测试功能。@delica我有一个问题。通常情况下,什么让答案被接受?通常情况下,什么让答案被标记为有用?我会说,如果它起作用,那么它就被接受为答案。如果它不起作用,那么接受它就没有意义,因为其他人会认为它已经解决了,不会发布更多的答案。This运行得很好,只是它通常会缩短太多:5.273913272867031E12->5273913272867(例如,从20到13个字符)。@delica很高兴知道,但我把精确解留给你来解决。特别是当你深入了解问题时。祝你好运谢谢你的部分解决方案!谢谢!