我正在尝试创建一个与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;
}
有一个问题,当一个变量是一个整数/ 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应该在二进制架构上精确,我想。
答案 0 :(得分:0)
就像你说的那样,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个元素),在两个不同的近似值之间的边界上精确,因此无论哪个返回都是任意的。