双精度和小数点
double precision and peridoc decimals
我正在研究一个Lisp解释器并实现了有理数。我认为他们比双打更有优势,能够代表像 1/3 这样的数字。我做了一些计算来比较结果。我对结果感到惊讶
带双打
(* 3.0 (/ 1.0 3.0)) -> 1
(* 3.0 (/ 4.0 3.0)) -> 4
(* 81.0 (/ 1.0 81.0)) -> 1
带比率:
(* 3 (/ 1 3)) -> 1
(* 3 (/ 4 3)) -> 4
(* 81 (/ 1 81)) -> 1
为什么浮点运算的结果是精确的?一定是精度的损失。双精度不能存储无限位数。还是我错过了什么?
我用一个小的C应用程序做了一个快速测试。相同的结果。
#include <stdio.h>
int main()
{
double a1 = 1, b1 = 3;
double a2 = 1, b2 = 81;
printf("result : %fn", a1 / b1 * b1);
printf("result : %fn", a2 / b2 * b2);
return 0;
}
输出为:
结果 : 1.000000
结果 : 1.000000
制造
马丁
对于第一种情况,乘法的确切结果介于 1.0 和小于 1.0 的最大双精度之间。根据 IEEE 754 舍入到最接近的规则,中间数字四舍五入为偶数,在本例中为 1.0。实际上,乘法结果的舍入抵消了除法结果四舍五入引入的误差。
这个 Java 程序说明了正在发生的事情。转换为 BigDecimal 和 BigDecimal 算术运算都是精确的:
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
double a1 = 1, b1 = 3;
System.out.println("Final Result: " + ((a1 / b1) * b1));
BigDecimal divResult = new BigDecimal(a1 / b1);
System.out.println("Division Result: " + divResult);
BigDecimal multiplyResult = divResult.multiply(BigDecimal.valueOf(3));
System.out.println("Multiply Result: " + multiplyResult);
System.out.println("Error rounding up to 1.0: "
+ BigDecimal.valueOf(1).subtract(multiplyResult));
BigDecimal nextDown = new BigDecimal(Math.nextAfter(1.0, 0));
System.out.println("Next double down from 1.0: " + nextDown);
System.out.println("Error rounding down: "
+ multiplyResult.subtract(nextDown));
}
}
输出为:
Final Result: 1.0
Division Result: 0.333333333333333314829616256247390992939472198486328125
Multiply Result: 0.999999999999999944488848768742172978818416595458984375
Error rounding up to 1.0: 5.5511151231257827021181583404541015625E-17
Next double down from 1.0: 0.99999999999999988897769753748434595763683319091796875
Error rounding down: 5.5511151231257827021181583404541015625E-17
第二种类似情况的输出为:
Final Result: 1.0
Division Result: 0.012345679012345678327022824305458925664424896240234375
Multiply Result: 0.9999999999999999444888487687421729788184165954589843750
Error rounding up to 1.0: 5.55111512312578270211815834045410156250E-17
Next double down from 1.0: 0.99999999999999988897769753748434595763683319091796875
Error rounding down: 5.55111512312578270211815834045410156250E-17
此程序说明了舍入误差可能累积的情况:
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
double tenth = 0.1;
double sum = 0;
for (int i = 0; i < 10; i++) {
sum += tenth;
}
System.out.println("Sum: " + new BigDecimal(sum));
System.out.println("Product: " + new BigDecimal(10.0 * tenth));
}
}
输出:
Sum: 0.99999999999999988897769753748434595763683319091796875
Product: 1
乘以 10 轮到 1.0。通过重复加法进行相同的乘法不会得到确切的答案。
相关文章:
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 正在将csv文件读取为双精度矢量
- 我可以信任表示整数的浮点或双精度来保持精度吗
- 如何在C++中的同一函数中使用字符串和双精度
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- 检查是否以特定精度给出双精度
- 转换函数,将 std::数组的双精度作为参数或双精度作为参数单独转换
- C 字符串返回字符串的整数/双精度/长整型值
- 双精度 10 小数点精度
- 如何使双精度始终具有三个小数点?C++
- 小数点后的数字,用于双精度变量/C++计算
- 双精度和小数点
- 变体浮点数到双精度值转换,四舍五入到小数点后 1 位
- 将双精度值的格式设置为小数点后 1 位
- C++将双精度中的每个小数点制作成数组元素
- 如何将双精度四舍五入到小数点后n位c++
- 如何在小数点后保留0,将字符串转换为双精度
- 即使使用长双精度(c++),结果也只有小数点后5位
- 将双精度值四舍五入到小数点后3位
- 如何将双精度转换为小数点后两位