- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在做一个将 RGB 转换为亮度的项目,但我遇到了一些与 -mno-sse2 标志有关的舍入问题:
测试代码如下:
#include <stdio.h>
#include <stdint.h>
static double rec709_luma_coeff[3] = {0.2126, 0.7152, 0.0722};
int main()
{
uint16_t n = 242 * rec709_luma_coeff[0] + 242 * rec709_luma_coeff[1] + 242 * rec709_luma_coeff[2];
printf("%u\n", n);
return 0;
}
这是我得到的:
user@gentoo>gcc -mno-sse2 test.c -o test && ./test
241
user@gentoo> gcc test.c -o test && ./test
242
我想 gcc 对 double
乘法使用 sse2 优化,但我不明白为什么优化版本会是正确的。
此外,您建议我使用什么来获得更一致的结果,ceil()
或 floor()
?
最佳答案
TL:DR 使用 lrint(x)
或 (int)rint(x)
将 float 转换为 int,使用舍入到最近而不是截断。不幸的是,并非所有编译器都能有效地内联相同的数学函数。参见 round() for float in C++
gcc -mno-sse2
必须为 double
使用 x87,即使在 64 位代码中也是如此。 x87 寄存器的内部精度为 80 位,但 SSE2 使用 IEEE binary64 (aka double
)在 XMM 寄存器中原生格式化,因此所有临时值在每一步都舍入为 64 位 double
。
这个问题没有the double rounding problem 有趣。 (80 位 -> 64 位,然后是整数)。它也不是来自 gcc -O0
(默认:没有额外的优化)在将临时对象存储到内存时舍入,因为你在一个 C 语句中完成了整个事情,所以它只对整个表达式使用 x87 寄存器.
只是 80 位精度导致结果刚好低于 242.0 并被 C 的 float->int 语义截断为 241,而 SSE2 产生的结果刚好高于 242.0,截断为 242 . 对于 x87,对于从 1 到 65535 的任何输入,向下舍入到下一个较低的整数是一致的,而不仅仅是 242。(我使用 atoi(argv[1])
制作了你的程序的一个版本所以我可以使用 -O3
测试其他值。
请记住 int foo = 123.99999
是 123,因为 C 使用“截断”舍入模式(接近零)。对于非负数,这与 floor
(向 -Infinity 舍入)相同。 https://en.wikipedia.org/wiki/Floating-point_arithmetic#Rounding_modes .
double
不能准确表示系数:我用 gdb
打印它们并得到:{0.21260000000000001, 0.71519999999999995, 0.0722}
。这些十进制表示可能不是以 2 为底的浮点值的精确表示。但它们非常接近,可以看出系数加起来为 0.99999999999999996
(使用任意精度计算器)。
我们得到consist rounding down是因为x87内部精度高于系数的精度,所以在n * rec709_luma_coeff[0]
等中求和舍入误差,在求和结果, 是 ~2^11
小于系数之和与 1.0 之间的差值。 (64 位有效数与 53 位)。
真正的问题是 SSE2 版本如何运作!大概舍入到最近——即使在临时对象上也恰好在足够多的情况下向上,至少对于 242。它恰好在更多情况下产生原始输入,但它为 5、7、10、13 产生输入 1, 14、20...(从 1..1000 开始的前 1000 个数字中有 252 个被 SSE2 版本“篡改”了,所以它也不总是有效。)
使用 -O3
作为您的源代码,它会在编译时以更高的精度进行计算并产生准确的结果。即它的编译与 printf("%u\n", n);
相同。
顺便说一句,你应该为常量使用 static
const
以便 gcc 可以更好地优化。不过,static
比普通的 global 好得多,因为编译器可以看到编译单元中没有任何内容写入值或将它们的地址传递到任何地方,因此它可以将它们视为 const
。
关于c - gcc -mno-sse2 四舍五入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35069186/
我有这个“科学应用程序”,其中 Single 值在显示在 UI 中之前应该四舍五入。根据this MSDN article ,由于“精度损失”,Math.Round(Double, Int32) 方法
这个问题类似于Chrome 37 calc rounding 但实际问题有点复杂,提供的解决方案不适用于这种情况: #outerDiv, #leftDiv, #middleDiv, #rightDiv
假设有一堆从 pnorm() 返回的数据,这样您就有了 .0003ish 和 .9999ish 之间的数字。 numbers <- round(rnorm(n = 10000, mean =
我想有效地将unsigneda整数除以2的任意幂,然后取整。所以我在数学上想要的是ceiling(p/q)0。在C语言中,不利用q受限域的Strawman实现可能类似于以下function1: /
我正在尝试获取 #value_box 的值以显示 100.5 但它一直在向上舍入。有谁知道我可以做些什么来让它显示小数位? jsfiddle //returns 101 $("#value_box
我有一段 JavaScript 代码 shipingcostnumber * parseInt(tax) / 100 + shipingcostnumber 返回数字为6655.866558,因此我将
我有一个关于 PostgreSQL 9.2 中 float 的新手问题。 是否有直接舍入 float 的函数,即不必先将数字转换为数字类型? 另外,我想知道是否有一个函数可以按任意度量单位舍入,例如最
这个问题已经有答案了: Rounding to nearest 100 (7 个回答) 已关闭10 年前。 我正在尝试将数字四舍五入到 100。 示例: 1340 should become 1400
我试图找出使用整数存储在列表中的其他两个数字之间的任何n在整数列表中找到最接近的值ROUNDED DOWN的最佳方法。在这种情况下,所有整数都将始终是无符号的,以防万一。 假设如下: 列表始终从0开始
我想将一个 BigDecimal 四舍五入到小数点后两位,但是当使用 round 方法时,它似乎没有双舍入: BigDecimal.new('43382.0249').round(2).to_s('F
我正在使用格式如下的财务数据进行计算: . 基本上,在我的程序中我遇到了一个浮点错误。例如,如果我有: 11.09 - (11.09 * 0.005) = 11.03455 我希望能够使用 11.03
有整型变量,电压单位为毫伏。 signed int voltage_mv = 134; //134mV 我有 2 段显示,我想显示百分之一伏特。 如何在一次操作中将毫伏转换为百分之一伏?没有 IF 语
这是我将数字四舍五入到两位小数的函数,但是当四舍五入的数字为 1.50 时,它似乎忽略尾随零并只返回 1.5 public static double roundOff(double number)
您好,我在将数字四舍五入到 -0 而不是 0 时遇到了问题 代码: 输出:-0 预期输出:0 我一直在寻找任何解决方案,但没有找到。 请解释并帮助我为什么它四舍五入为 -0 而不是 0?谢谢 最佳答
我正在使用 Java 的 Random 生成随机数:1.0、1.1 - 10 Random random = new Random(); return (double) ((random.nextIn
基本上,我有一个数字: 我基本上想做一些数学运算来创建这个数字 80。 如果数字是 62.7777777778,则数字将为 60。 我希望数字像这样四舍五入: 20, 40, 60, 80, 100
我希望显示来自 NSDate 对象的月数。 //Make Date Six Months In The Future NSCalendar *calendar = [[NSCalendar alloc
下面是一些小代码来说明我所看到的 float floater = 59.999f; DecimalFormat df = new DecimalFormat("00.0"); System.out.p
我现在开始使用 android 和 java,但遇到了问题。 I have a result x = 206.0548. And y = 206, both of type double How do
我有一个 ruby 散列数组,其中包含两个键,'tier' 和 'price'。对于给定的价格,我想退回等级。 这对于精确匹配来说已经足够简单了,但是我如何通过将我的输入值四舍五入到数组中的下一个
我是一名优秀的程序员,十分优秀!