floating-point - 查明从十进制到二进制浮点的转换是否准确、向上舍入或向下舍入
问题描述
我知道可以用十进制浮点数精确表示的值通常无法用二进制浮点数表示为精确值。在例如 python 中很容易演示
a = float("0.5")
print('%.17e' % (a))
5.00000000000000000e-01
a = float("0.054")
print('%.17e' % (a))
5.39999999999999994e-02
a = float("0.055")
print('%.17e' % (a))
5.50000000000000003e-02
这完全是意料之中的,也是完全正确的。但我想知道的是,是否有一种简单的方法可以找出转换后的值是高于还是低于确切值(或者实际上是否准确地转换)。从上面的例子中,我显然可以对输出字符串做一些事情,但这看起来非常笨拙,知道这是一件非常有用的事情(例如,如果你在循环中增加一个浮点数,你可以用它来决定你是否是否会获得预期的迭代次数),我希望有一种更直接的方法来做到这一点。我在这里仅使用 python 作为示例 - 我更喜欢语言不可知的解决方案。
解决方案
对于某些语言,在选择条件下,代码可以通过最接近、向上或向下(或向 0,或...)的转换来控制舍入模式。
然后可以将默认(通常到最近)的转换结果与up或down进行比较。
#include <fenv.h>
#include <assert.h>
#include <stdio.h>
double string_to_double(int round_dir, const char *s) {
#pragma STDC FENV_ACCESS ON
int save_round = fegetround();
int setround_ok = fesetround(round_dir);
assert(setround_ok == 0);
char *endptr;
double d = strtod(s, &endptr);
fesetround(save_round);
return d;
}
// Return 1: up, -1: down, 0: exact
int updn(const char *s) {
double up = string_to_double(FE_UPWARD, s);
double nr = string_to_double(FE_TONEAREST, s);
double dn = string_to_double(FE_DOWNWARD, s);
// Others modes: FE_TOWARDZERO
printf("%.17e, %.17e, %.17e, ", dn, nr, up);
if (up == dn) {
assert(up == nr);
return 0;
}
if (up > nr) return -1;
if (dn < nr) return 1;
return 0; // Unexpected, unless NaN
}
int main() {
printf("%2d\n", updn("0.5"));
printf("%2d\n", updn("0.054"));
printf("%2d\n", updn("0.055"));
}
输出:1:向上,-1:向下,0:精确
5.00000000000000000e-01, 5.00000000000000000e-01, 5.00000000000000000e-01, 0
5.39999999999999994e-02, 5.39999999999999994e-02, 5.40000000000000063e-02, -1
5.49999999999999933e-02, 5.50000000000000003e-02, 5.50000000000000003e-02, 1
推荐阅读
- sql - 如何在 Amazon Redshift 中提取两个括号之间的数字?
- sql-server - 需要避免sql表中的重复结果
- python-3.x - 使用包含索引元组的键从字典创建一个 numpy 数组
- c# - FileSystemWatcher 只显示内存地址,不显示更改文件的名称
- spring-mvc - 在 @RestController 上使用 Spring @PageableDefault 时忽略分页参数
- c++ - QTabWidget 隐藏和显示选项卡
- css - 按绝对位置居中在 Chrome 中可以正常工作,但在最新版本的 IE 和 Firefox 中不行
- php - Woocommerce 单一变体价格显示不符合预期
- c# - PCI Express如何使用C#连接读写
- markdown - Strapi WYSIWYG markdown 编辑器中的上标和下标