如果可以使用float
正确表示我将使用的参数范围,我试图找出我的音频应用程序。
它所需的“最大”掩模是频率参数,它是正的,并且允许最多两位数作为尾数(即从20. 00 hz到22000. 00 hz)。从概念上讲,以下数字将被四舍五入,所以我不关心它们。
所以我做了这个script来检查以单精度碰撞的第一个数字:
float temp = 0.0;
double valueDouble = 0.0;
double increment = 1e-2;
bool found = false;
while(!found) {
double oldValue = valueDouble;
valueDouble += increment;
float value = valueDouble;
// found
if(temp == value) {
std::cout << "collision found: " << valueDouble << std::endl;
std::cout << " collide with: " << oldValue << std::endl;
std::cout << "float stored as: " << value << std::endl;
found = true;
}
temp = value;
}
它似乎是131072.02
(131072.01
,存储为相同的131072.015625
值),远远超过22000.00。似乎我可以使用浮动。
但我想了解这种推理是否正确。是吗?
如果我设置一个XXXXX.YY(7 digits
)的参数并且它与其他一些数字较少的数字发生冲突(因为single precision
仅保证6 digits
,整个问题就出现了。 })
注意:当然1024.0002998145910169114358723163604736328125
或1024.000199814591042013489641249179840087890625
之类的数字会发生碰撞,并且它们在这个区间内,但它们的数字长度超过我所需的尾数,所以我不在乎
答案 0 :(得分:3)
在22k处,指数将表示16384 = 2 ^ 14的偏移,因此23位尾数将给出精度2 ^ 14/2 ^ 23 = 1/2 ^ 9 = 0.001953125 ...这是足以满足您的需求。
对于131072.01,指数将表示偏移量131072 = 2 ^ 17,因此尾数将给出2 ^ 17/2 ^ 23 = 1/2 ^ 6 = 0.015625的精度,其大于目标精度0.01
答案 1 :(得分:1)
您的程序无法准确验证您的需求,但您的基本推理应该没问题。
该程序存在的问题是valueDouble会累积一些小错误(因为0.01并未准确表示) - 并转换字符串&#34; 20.01&#34;浮点数会引入轻微的舍入错误。
但是这些错误应该是DBL_EPSILON的顺序,并且比你看到的错误要小得多。
如果你真的想测试它,你必须写&#34; 20.00&#34;至&#34; 22000.00&#34;并使用您计划使用的scanf-variant扫描它们并验证它们是否不同。
答案 2 :(得分:1)
说明以单精度碰撞的第一个数字是131072.02是否正确? (正,考虑2位数
作为小数点后的尾数)
是
我想了解这种推理是否正确。是吗?
对于小于131072.0f的值,每个连续可表示的float
值相差1/128。
对于[131072.0f ... 2 * 131072.0f]范围内的值,每个连续可表示的float
值相差1/64。
使用十进制文本格式&#34; 131072.xx&#34;的值,有100种组合,但只有64种不同float
。发生100-64或36 collisions并不奇怪 - 见下文。对于此形式的数字,这是float
的密度太稀疏的第一个位置:float
中的最低有效位&gt;在此范围内为0.01。
int main(void) {
volatile float previous = 0.0;
for (long i = 1; i <= 99999999; i++) {
volatile float f1 = i / 100.0;
if (previous == f1) {
volatile float f0 = nextafterf(f1, 0);
volatile float f2 = nextafterf(f1, f1 * 2);
printf("%f %f %f delta fraction:%f\n", f0, f1, f2, 1.0 / (f1 - f0));
static int count = 100 - 64;
if (--count == 0) return 0;
}
previous = f1;
}
printf("Done\n");
}
输出
131072.000000 131072.015625 131072.031250 delta fraction:64.000000
131072.031250 131072.046875 131072.062500 delta fraction:64.000000
131072.046875 131072.062500 131072.078125 delta fraction:64.000000
...
131072.921875 131072.937500 131072.953125 delta fraction:64.000000
131072.937500 131072.953125 131072.968750 delta fraction:64.000000
131072.968750 131072.984375 131073.000000 delta fraction:64.000000
Why floating-points number's significant numbers is 7 or 6也可以提供帮助。