2017-04-17 2 views
0

J'ai un problème avec un script, je ne comprends pas ce qui se passe.requestAnimationFrame ne fonctionne pas comme prévu

Ici, il est:

let angle = 0 
let multiplier = .01 

function raf() { 

    if(angle >= 1 || angle < 0) { 
    multiplier = - multiplier 
    } 

    angle = angle + multiplier 

    if(angle < 0) console.log(angle) 

    requestAnimationFrame(raf) 
} 

requestAnimationFrame(raf) 

Le but est l'angle d'augmenter de 0,01 et quand il atteint 1, il devrait diminuer à 0 puis soulever de nouveau à 1.

Je reçois parfois un angle négatif (-8.etc) et je ne comprends pas pourquoi (le console.log est supposé le montrer).

J'ai fait un stylo pour que: https://codepen.io/mourtazag/pen/QvjjLy

Merci à tous!

Mourtaza.

Répondre

0

Vous n'avez pas recevoir -8, vous recevez -8.XXXXXXe-17. Notez le e-17 à la fin. C'est la notation scientifique, donc votre numéro est en réalité -0.00000000000000008XXXXX. Vous pouvez voir le nombre float sans notation scientifique en utilisant angle.toFixed(20). Le nombre est le nombre de décimales que vous voulez montrer. Pourquoi avez-vous des nombres aussi petits si vous augmentez et diminuez seulement de 0.01? pouvez-vous demander. Cela arrive parce que les points flottants ne sont pas exacts car les nombres décimaux sont impossibles à "enregistrer jusqu'à la fin", pas comme les nombres entiers. Pensez à 1/3 ayant un nombre infini de décimales, par exemple. Ici vous pouvez en savoir plus sur JavaScript et la précision du flotteur: Dealing with float precision in Javascript

L'autre problème est d'avoir un angle négatif (si petit, mais toujours négatif même si vous vérifiez réellement les angles négatifs). Cela se produit parce que vous vérifiez les angles négatifs AVANT de l'augmenter/diminuer, donc si vous avez votre multiplicateur comme négatif et votre angle comme, disons, 0.0001whatever (à cause du problème de précision du flotteur), il est toujours supérieur à zéro, donc vous multipliez toujours être négatif, mais est en fait plus grand que votre angle, donc quand le multiplicateur est appliqué, l'angle sera négatif.

Je peux penser à cette façon de résoudre ce problème:

let angle = 0 
let multiplier = .01 

function raf() { 

    angle = angle+multiplier; 

    if(angle > 1 || angle < 0) { 
    multiplier = -multiplier 
    angle = angle<0?0:1; 
    } 
    console.log(angle.toFixed(20)) 

    requestAnimationFrame(raf) 
} 

requestAnimationFrame(raf) 

Avec cela, vous vérifiez si votre angle est à l'intérieur des limites retravaillée, de sorte que vous surmonterez le problème de précision: https://codepen.io/anon/pen/eWppGy

Une autre façon peut être d'utiliser des entiers (parce qu'ils ne sont pas le problème de précision, comme je l'ai dit ci-dessus) et de diviser l'angle par 100 pour aller au travail avec elle, comme ceci:

let angle = 0 
let multiplier = 1 

function raf() { 

    angle = angle+multiplier; 

    if(angle >= 100 || angle <= 0) { 
    multiplier = -multiplier; 
    angle = angle<=0?0:100; 
    } 
    console.log(angle/100) 

    requestAnimationFrame(raf) 
} 

requestAnimationFrame(raf) 

Stylo: https://codepen.io/anon/pen/XRmmVq

+1

Merci! Je comprends le problème et votre solution fonctionne bien! :) – Mourtazag

+0

@Mourtazag Heureux qu'il a aidé: P –

0

Vous rencontrez un cas de mathématiques du point de Floating malheureux

0.94 - 0.01 
0.9299999999999999 

Ces erreurs peuvent complexifier puisque vous soustrayez 0,01 de plus en plus de fois de manière à la fin au lieu de faire de 0,01 à 0,01, qui obtiendrait 0, le code est plutôt faire quelque chose comme

0.009999999999999247 - 0.01 

qui est légèrement négative. Vous pourriez probablement juste lier le min et le max avec Math.max (0, yourValue) et Math.min (1, yourValue) si vous avez besoin que ceci soit borné comme ça.

0

Il est un point flottant question

var a = 0; 
 
for (var i = 0; i < 100; ++i) { 
 
    a += 0.01; 
 
} 
 
console.log(a); 
 
for (var i = 0; i < 101; ++i) { 
 
    a -= 0.01; 
 
} 
 
console.log(a); 
 
a += 0.01; 
 
console.log(a);

impressions

1.0000000000000007 
-0.010000000000000087 
-8.673617379884035e-17 

envisager d'utiliser des entiers ou une horloge et calculer l'angle de ceux

0

Hors sujet: Une approche différente de l'angle. En fonction du temps passé plutôt que du changement incrémental.

let start = Date.now(); 
 
let speed = 1/10000; //1 in every 10 seconds 
 

 
function raf() { 
 
\t let v = (Date.now() - start) * speed; 
 
\t let angle = v&1? 1-v%1: v%1; 
 
\t \t 
 
\t document.body.textContent = "Angle: " + angle.toFixed(3); 
 
\t requestAnimationFrame(raf); 
 
} 
 

 
//or with some sugar: 
 
speed = 180/10000; 
 
function raf() { 
 
    let minAngle = -90, maxAngle = 90, delta = maxAngle - minAngle; 
 

 
\t let v = (Date.now() - start) * speed; 
 
\t let angle = (v/delta)&1? maxAngle-v%delta: minAngle + v%delta; 
 
\t \t 
 
\t document.body.textContent = "angle: " + angle.toFixed(3); 
 
\t requestAnimationFrame(raf); 
 
} 
 

 
raf();

ou avec du sucre; le calcul entier quand on ne parle pas d'une plage de 0 à 1

let start = Date.now(); 
 
let speed = 180/10000; 
 
let minAngle = -30, maxAngle = 45; 
 

 
function raf() { 
 
\t let delta = maxAngle - minAngle; 
 
\t let v = (Date.now() - start) * speed; 
 
\t let backwards = (v/delta)&1; 
 
\t let angle = backwards? maxAngle - v%delta: minAngle + v%delta; 
 

 
\t document.body.textContent = "angle: "+ angle.toFixed(3) +", direction: " + (backwards? "backward": "forward"); 
 

 
\t requestAnimationFrame(raf); 
 
} 
 

 
raf();