将 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 个元素),您 精确地 在两个不同近似值之间的边界上,因此无论返回哪个都是任意的。