KJ7LNW
KJ7LNW

Reputation: 1901

Does Perl PDL have an equivalent of Math::Round::nearest()?

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]

Upvotes: 2

Views: 141

Answers (2)

PeterCJ
PeterCJ

Reputation: 146

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()"

Upvotes: 3

Ed.
Ed.

Reputation: 2062

Such a thing could be added, but would need to be specified a bit more clearly; what would it do with negative numbers? And how would it differ from floor / ceil / rint?

Upvotes: 2

Related Questions