数字存储在数据库中(在我的控件之外)作为浮点数/双打等。
当我将它们拉出来时,它们已损坏 - 例如0.1
将出现(格式化时)为0.100000001490116119384765625
。
是否有可靠的方法来恢复这些数字?
我尝试了new BigDecimal(((Number) o).doubleValue())
和BigDecimal.valueOf(((Number) o).doubleValue())
,但这些都不起作用。我仍然得到了损坏的结果。
我知道我可以对小数位数进行假设并对它们进行舍入,但这会打破例如故意为0.33333333333的数字。
是否有一种适用于大多数理性的简单方法?
我想我问是否有一种简单的方法可以找到浮点数的小三角区内最小的有理数?。
答案 0 :(得分:0)
您可以将数字作为字符串存储在数据库中,也可以将它们存储在parseDouble()中。这样,数字就不会被损坏,就像你在那里存放一样。
答案 1 :(得分:0)
有一种简单的方法可以找到一个在浮点数的0.00001范围内的有理数吗?
这称为四舍五入。
double d = ((Number) o).doubleValue();
double d2 = Math.round(d * 1e5) / 1e5;
BigDecimal bd = BigDecimal.valueOf(d2);
或者你可以使用BigDecimal来执行舍入(我避免使用BigDecimal,因为一旦你知道如何使用舍入双精度,它就会非常慢)
double d = ((Number) o).doubleValue();
BigDecimal bd = BigDecimal.valueOf(d).setScale(5, RoundingMode.HALF_UP);
注意:除非您了解它的作用,否则永远不要使用new BigDecimal(double)
。最有可能BigDecial.valueOf(double)
是你想要的。
答案 2 :(得分:0)
这是我做过的棒球方式 - 我欢迎更优雅的解决方案。
我选择Rational
mediant
long
为我准备了int
方法。
我重构它以使用// Default delta to apply.
public static final double DELTA = 0.000001;
public static Rational valueOf(double dbl) {
return valueOf(dbl, DELTA);
}
// Create a good rational for the value within the delta supplied.
public static Rational valueOf(double dbl, double delta) {
// Primary checks.
if ( delta <= 0.0 ) {
throw new IllegalArgumentException("Delta must be > 0.0");
}
// Remove the integral part.
long integral = (long) Math.floor(dbl);
dbl -= integral;
// The value we are looking for.
final Rational d = new Rational((long) ((dbl) / delta), (long) (1 / delta));
// Min value = d - delta.
final Rational min = new Rational((long) ((dbl - delta) / delta), (long) (1 / delta));
// Max value = d + delta.
final Rational max = new Rational((long) ((dbl + delta) / delta), (long) (1 / delta));
// Start the fairey sequence.
Rational l = ZERO;
Rational h = ONE;
Rational found = null;
// Keep slicing until we arrive within the delta range.
do {
// Either between min and max -> found it.
if (found == null && min.compareTo(l) <= 0 && max.compareTo(l) >= 0) {
found = l;
}
if (found == null && min.compareTo(h) <= 0 && max.compareTo(h) >= 0) {
found = h;
}
if (found == null) {
// Make the mediant.
Rational m = mediant(l, h);
// Replace either l or h with mediant.
if (m.compareTo(d) < 0) {
l = m;
} else {
h = m;
}
}
} while (found == null);
// Bring back the sign and the integral.
if (integral != 0) {
found = found.plus(new Rational(integral, 1));
}
// That's me.
return found;
}
public BigDecimal toBigDecimal() {
// Do it to just 4 decimal places.
return toBigDecimal(4);
}
public BigDecimal toBigDecimal(int digits) {
// Do it to n decimal places.
return new BigDecimal(num).divide(new BigDecimal(den), digits, RoundingMode.DOWN).stripTrailingZeros();
}
代替d
,然后添加:
1/10
基本上 - 算法的范围为0-1。在每次迭代中,我检查范围的任何一端是否落在我的d-delta-d + delta范围之间。如果确实如此,我们就找到了答案。
如果找不到答案,我们会取两个限制的implementation并用它替换其中一个限制。选择替换限制以确保始终围绕0.100000001490116119384765625
的限制。
这实质上是在0和1之间进行二进制搜索,以找到落在所需范围内的第一个理性。
在数学上我向下爬mediant选择那个让我包围所需数字的分支,直到我落入所需的三角形。
注意:我还没有完成测试,但我确实找到了1/3
1.0/3.0
和355/113
{{1}}以及经典{{1}} π