将 sin() 近似为 {1, 0, -1} 会给出错误的结果
Approximate sin() to {1, 0, -1} gives wrong results
我正在尝试创建一个近似于 sin() 的函数,以便它取值 1、0 或 -1。此代码
var periodicity = 2 * Math.PI;
var sin3 = function(t) {
var tmod = (t / periodicity) % 1;
if (tmod < 1/8)
return 0
else if (tmod < 3/8)
return Math.sign(tmod)
else if (tmod < 5/8)
return 0
else if (tmod < 7/8)
return -Math.sign(tmod)
else return 0;
}
有一个问题,当一个变量是一个 integer/8 时,它有时会得到一个不一致的值。例如代码
for (i = 0; i < 32; i++) {
sin3(i/8*2*Math.PI)
}
获取值
[0, 1, 1, 0, 0, -1, -1, 0, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 0, 0, -1, -1, 0, 0, 1, 1, 0, 0, -1, -1, 0]
第12个元素本应为0却变成了1。
第16个元素本应为0却变成了-1.
将周期更改为 1 没有帮助。我认为在二进制架构上使用增量 2^-n 应该是精确的。
这是一个fiddlehttp://jsfiddle.net/ephyckf1/1/
正如您所说,i/8
具有精确的二进制表示。
因此 (i/8) * ((2*Math.PI) / (2*Math.PI))
不会出现浮点舍入错误,但是 (i/8*2*Math.PI) / (2*Math.PI)
会出现 。这是因为中间结果 (i/8*2*Math.PI)
没有精确的浮点表示。
话虽如此,何苦呢?对于 i
的每个奇数值(包括第 12 和第 16 个元素),您 精确地 在两个不同近似值之间的边界上,因此无论返回哪个都是任意的。
我正在尝试创建一个近似于 sin() 的函数,以便它取值 1、0 或 -1。此代码
var periodicity = 2 * Math.PI;
var sin3 = function(t) {
var tmod = (t / periodicity) % 1;
if (tmod < 1/8)
return 0
else if (tmod < 3/8)
return Math.sign(tmod)
else if (tmod < 5/8)
return 0
else if (tmod < 7/8)
return -Math.sign(tmod)
else return 0;
}
有一个问题,当一个变量是一个 integer/8 时,它有时会得到一个不一致的值。例如代码
for (i = 0; i < 32; i++) {
sin3(i/8*2*Math.PI)
}
获取值
[0, 1, 1, 0, 0, -1, -1, 0, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 0, 0, -1, -1, 0, 0, 1, 1, 0, 0, -1, -1, 0]
第12个元素本应为0却变成了1。 第16个元素本应为0却变成了-1.
将周期更改为 1 没有帮助。我认为在二进制架构上使用增量 2^-n 应该是精确的。
这是一个fiddlehttp://jsfiddle.net/ephyckf1/1/
正如您所说,i/8
具有精确的二进制表示。
因此 (i/8) * ((2*Math.PI) / (2*Math.PI))
不会出现浮点舍入错误,但是 (i/8*2*Math.PI) / (2*Math.PI)
会出现 。这是因为中间结果 (i/8*2*Math.PI)
没有精确的浮点表示。
话虽如此,何苦呢?对于 i
的每个奇数值(包括第 12 和第 16 个元素),您 精确地 在两个不同近似值之间的边界上,因此无论返回哪个都是任意的。