I am working on some code that calculates percentiles and am running into issues in Mata. Digging into it, I found that the mod() operator wasn't acting as expected in either Mata or Stata. Going one level deeper, I found that numerical precision problems are the issue, that arise even when applied to relatively small numbers.
Initially, I was looking at a case where A/(B/C) != A/B*C.
So the solution could be to manually write out a revised definition of mod(x,y) each time I wan't to use mod(). Ie define
mod(x,y) = x-y*floor(float(x/y))
Then I started seeing another case, where A*B/C != A/C*B
So define yet a new version of the mod(x,y)
mod(x,y) = x-float(y*floor(float(x/y)))
What is causing this?
Thanks,
Andrew Maurer
Initially, I was looking at a case where A/(B/C) != A/B*C.
Code:
// 75th percentile sometimes fails // eg mod(588,784/20) di mod(588,39.2) di 588/39.2 // This should be exactly 15 di 588-39.2*floor(588/39.2) // Returns 39.2. What!? di 588-39.2*floor(float(588/39.2))==0 // Float solution returns 0. So it's a precision issue... di 15 == 588/39.2 // False di 15 == 588/(784/20) // False di 15 == 588/784*20 // True... Weird!!
mod(x,y) = x-y*floor(float(x/y))
Then I started seeing another case, where A*B/C != A/C*B
Code:
// 55th percentile sometimes fails // eg 3916-float(7120*55/100) scalar x = 3916 scalar y = 7120*11/20 // This should be exactly 3916 di mod(x,y) // Returns 3916... Wrong! di x-y*floor(float(x/y)) // Float solution from above doesn't work! Returns -4.547e-13 (nonzero) di x-y*floor(float(x/y))==0 // False (implied by above) di x-float(y*floor(float(x/y)))==0 // True. Gah, finally! Man is this ever a kludge di 3916 == 7120*55/100 // False di 3916 == 7120/100*55 // True... Weird!!
mod(x,y) = x-float(y*floor(float(x/y)))
What is causing this?
Thanks,
Andrew Maurer
Comment