mod gives incorrect result
Afficher commentaires plus anciens
Here is a mathematical error with a simple expression:
>> mod(-sin(pi),512)
ans =
512
Of course, pi isn't exact, so sin(pi) gives a small negative number. That isn't good, but it is perhaps excusable. However, that mod(X, 512) ever returns 512 is totally unacceptable.
2 commentaires
Steve
le 31 Juil 2013
the cyclist
le 3 Août 2013
Modifié(e) : the cyclist
le 3 Août 2013
Another workaround would be to apply the mod function twice. [This is another indication that mod()'s output is a bit mathematically silly in this case.]
Réponses (3)
Walter Roberson
le 31 Juil 2013
1 vote
In order to understand this, you need to look at the fact that -sin(pi) is a negative value that has a very small magnitude (due to standard round-off issues), so mod(-sin(pi), 512) is 512-sin(pi) . But sin(pi) is less than eps(512), so 512-sin(pi) is most closely representable as 512 itself.
This is, I agree, not what I would have expected, but I had never really thought about the matter before.
Would it be better if mod(x, P) with positive P and x in (-eps(P), 0) (exclusive) be 0? Arguable, but it is not obvious to me that that possible outcome would be better than the current outcome.
1 commentaire
the cyclist
le 1 Août 2013
In essence, what is happening here is that the tiny floating point error is going through an "amplifier". It is analogous to expecting
(1 - 2/3 - 1/3)*1e17
to be 0, but it turns out to be about 5.5.
So, there is the usual aspect of "let the buyer beware" if floating point error can give a big difference in your results.
In this particular case, though, I would argue that 512 as the "most closely representable" is less compelling, because 512 is not in the theoretical range of the mod() function, mathematically. I know it sounds odd, but I think that 0 is the most closely representable number to 512-eps in this case. Mathematically,
Limit mod(512-eps,512)
{eps->0}
is zero, not 512.
Wayne King
le 31 Juil 2013
Modifié(e) : Wayne King
le 31 Juil 2013
Are you sure you're not confusing mod() with rem()?
If you read the help for mod(), it says that
mod(x,y) returns x-floor(x/y)*y
rem(x,y) returns x-fix(x/y)*y
-sin(pi)-floor(-sin(pi)/512)*512
is 512 because
floor(-sin(pi)/512)
is -1.
so essentially 0+(1)*512 = 512
on the other hand
-sin(pi)-fix(-sin(pi)/512)*512
yields essentially
0-(0)*512=0
3 commentaires
the cyclist
le 31 Juil 2013
It's admirable that MATLAB is doing what it's documentation states, but mathematically
mod(x,N)
has a range of [0,N), strictly less than N.
Steve
le 31 Juil 2013
Wayne King
le 31 Juil 2013
I think "essentially 0" is warranted here since -sin(pi) is on the order of 10^(-16). For example:
rng default;
x = randn(10,1);
max(abs(ifft(fft(x))-x))
gives a value of 8x10^(-16) but nobody would say that the example above does NOT demonstrate perfect inversion of x.
Wayne King
le 31 Juil 2013
Modifié(e) : Wayne King
le 31 Juil 2013
If anybody's interested in this, google:
"division and modulus for computer scientists"
mod() is implementing what Knuth termed "floored division". It's also described here:
Just FYI, Python implements the same operation for % as MATLAB mod(), but R appears to be different. R's %% operator appears to mimic rem() in MATLAB.
So in Python:
>>>import Numpy as np
>>>-np.sin(np.pi)%512
returns 512.
In R
> -sin(pi)%%512
returns zero like MATLAB
rem(-sin(pi),512)
Catégories
En savoir plus sur Installation dans Centre d'aide et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!