Does PDL already have a way to apply a "rounding" to the vector elements by some precision in the way that Math::Round::nearest() does? I've looked through the PDL::Math documentation but didn't see a good candidate option.
I could unpdl/re-pdl but that seems like too much overhead.
Is there already a vectorized way to do this?
I tried something like this:
$pdl = pdl [4.45, 5.55, 45];
$n = pdl [.1, .3, 10];
print rint($pdl/$n)*$n
[4.4 5.4 40]
but as as you can see it doesn't quite work because it should round up to the nearest precision. This would be the "correct" output:
[4.5 5.6 50]
Per PDL::Math's rint
documentation, rint
uses "round half to even" (aka "banker's rounding"). They then go on to explain that to always round half up (regardless of sign, so 4.5 to 5.0 and -4.5 to -4.0), use floor($x+0.5)
, and to round half away from zero (so 4.5 to 5.0 and -4.5 to -5.0), use ceil(abs($x)+0.5)*($x<=>0)
I ran the following in the perldl
shell, adding some extra example numbers:
pdl> p $pdl = pdl [5.55, 45, 55, -45, -55, 4.45, 4.55, -4.45, -4.55]
[5.55 45 55 -45 -55 4.45 4.55 -4.45 -4.55]
pdl> p $n = pdl [.3, 10, 10, 10, 10, .1, .1, .1, .1]
[0.3 10 10 10 10 0.1 0.1 0.1 0.1]
pdl> p "bankers rounding: " => rint($pdl/$n)*$n
bankers rounding: [5.4 40 60 -40 -60 4.4 4.5 -4.4 -4.5]
pdl> p "round half up: " => floor($pdl/$n+0.5)*$n
round half up: [5.7 50 60 -40 -50 4.5 4.5 -4.4 -4.5]
pdl> p "round half away: " => ceil(abs($pdl/$n)+0.5)*(($pdl/$n)<=>0)*$n
round half away: [5.7 50 60 -50 -60 4.5 4.6 -4.5 -4.6]
Aside: On your "correct" output, I don't see how 5.55 rounded by 0.3 should be 5.6, as 5.6 is not a multiple of 0.3. The nearest multiple of 0.3 above 5.55 is 5.7.
Update: Looking at Math::Round::nearest(), it looks like it rounds toward infinity, so the "round half away" example would be what matches the behavior of "equivalent to Math::Round::nearest()"