Thread: rounding_up

rounding_up

From
Daria Shanina
Date:
Hello everyone!

I noticed, when we parse and validate values (in particular, the int type), we use the rint method, but unfortunately it does not work according to the round rules. Although on the website https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/rint-rintf-rintl?view=msvc-170 says something else.

I tested at several OS:


Lubuntu

daria-shanina@lnv-dshanina:~/projects/test$ ./rounding_up

rint(2.00) is 2.0 | round(2.00) is 2.0 | ceil(2.00) is 2.0 | floor(2.00) is 2.0

rint(2.10) is 2.0 | round(2.10) is 2.0 | ceil(2.10) is 3.0 | floor(2.10) is 2.0

rint(2.20) is 2.0 | round(2.20) is 2.0 | ceil(2.20) is 3.0 | floor(2.20) is 2.0

rint(2.30) is 2.0 | round(2.30) is 2.0 | ceil(2.30) is 3.0 | floor(2.30) is 2.0

rint(2.40) is 2.0 | round(2.40) is 2.0 | ceil(2.40) is 3.0 | floor(2.40) is 2.0

rint(2.50) is 2.0 | round(2.50) is 3.0 | ceil(2.50) is 3.0 | floor(2.50) is 2.0

rint(2.60) is 3.0 | round(2.60) is 3.0 | ceil(2.60) is 3.0 | floor(2.60) is 2.0

rint(2.70) is 3.0 | round(2.70) is 3.0 | ceil(2.70) is 3.0 | floor(2.70) is 2.0

rint(2.80) is 3.0 | round(2.80) is 3.0 | ceil(2.80) is 3.0 | floor(2.80) is 2.0

rint(2.90) is 3.0 | round(2.90) is 3.0 | ceil(2.90) is 3.0 | floor(2.90) is 2.0


FreeBSD

daria@2ndfreebsd:~/projects/test$ ./rounding_up

rint(2.00) is 2.0 | round(2.00) is 2.0 | ceil(2.00) is 2.0 | floor(2.00) is 2.0

rint(2.10) is 2.0 | round(2.10) is 2.0 | ceil(2.10) is 3.0 | floor(2.10) is 2.0

rint(2.20) is 2.0 | round(2.20) is 2.0 | ceil(2.20) is 3.0 | floor(2.20) is 2.0

rint(2.30) is 2.0 | round(2.30) is 2.0 | ceil(2.30) is 3.0 | floor(2.30) is 2.0

rint(2.40) is 2.0 | round(2.40) is 2.0 | ceil(2.40) is 3.0 | floor(2.40) is 2.0

rint(2.50) is 2.0 | round(2.50) is 3.0 | ceil(2.50) is 3.0 | floor(2.50) is 2.0

rint(2.60) is 3.0 | round(2.60) is 3.0 | ceil(2.60) is 3.0 | floor(2.60) is 2.0

rint(2.70) is 3.0 | round(2.70) is 3.0 | ceil(2.70) is 3.0 | floor(2.70) is 2.0

rint(2.80) is 3.0 | round(2.80) is 3.0 | ceil(2.80) is 3.0 | floor(2.80) is 2.0

rint(2.90) is 3.0 | round(2.90) is 3.0 | ceil(2.90) is 3.0 | floor(2.90) is 2.0


Windows

C:\Users\Daria\projects\test>rounding_up.exe

rint(2.00) is 2.0 | round(2.00) is 2.0 | ceil(2.00) is 2.0 | floor(2.00) is 2.0

rint(2.10) is 2.0 | round(2.10) is 2.0 | ceil(2.10) is 3.0 | floor(2.10) is 2.0

rint(2.20) is 2.0 | round(2.20) is 2.0 | ceil(2.20) is 3.0 | floor(2.20) is 2.0

rint(2.30) is 2.0 | round(2.30) is 2.0 | ceil(2.30) is 3.0 | floor(2.30) is 2.0

rint(2.40) is 2.0 | round(2.40) is 2.0 | ceil(2.40) is 3.0 | floor(2.40) is 2.0

rint(2.50) is 2.0 | round(2.50) is 3.0 | ceil(2.50) is 3.0 | floor(2.50) is 2.0

rint(2.60) is 3.0 | round(2.60) is 3.0 | ceil(2.60) is 3.0 | floor(2.60) is 2.0

rint(2.70) is 3.0 | round(2.70) is 3.0 | ceil(2.70) is 3.0 | floor(2.70) is 2.0

rint(2.80) is 3.0 | round(2.80) is 3.0 | ceil(2.80) is 3.0 | floor(2.80) is 2.0

rint(2.90) is 3.0 | round(2.90) is 3.0 | ceil(2.90) is 3.0 | floor(2.90) is 2.0


As you could see in the output, the round method works according to the rules. Maybe we should use it?


Thank you for your attention!


--

Best regards,

Daria Shanina


Re: rounding_up

From
Andrey Borodin
Date:
Hi Daria!

> On 14 Apr 2025, at 13:24, Daria Shanina <vilensipkdm@gmail.com> wrote:
>
> when we parse and validate values (in particular, the int type), we use the rint method, but unfortunately it does
notwork according to the round rules. 

Are this concerns explainable in SQL query?

As far as I can see from your data, rint() is consistent across OSes. Can user observe any inconsistency caused by
rint()behavior in PostgreSQL? 

Thanks!


Best regards, Andrey Borodin.


Re: rounding_up

From
Christoph Moench-Tegeder
Date:
Hi,

## Daria Shanina (vilensipkdm@gmail.com):

> I noticed, when we parse and validate values (in particular, the int type),
> we use the *rint* method, but unfortunately it does not work according to
> the round rules.

First question would be "which round rule?" as (of course) there're
multiple to chose from.

Second, the rules in use are consistent with the documentation of
round(double precision)
: Rounds to nearest integer. For numeric, ties are broken by rounding
: away from zero. For double precision, the tie-breaking behavior is
: platform dependent, but “round to nearest even” is the most common rule.
https://www.postgresql.org/docs/current/functions-math.html
and I think it makes sense to have round() and implicit rounding
behave the same.

Third, rint() works the way you set it to with fesetround() (see
man page). And that works on the nearest Linux and FreeBSD I
could grab :)

Regards,
Christoph

-- 
Spare Space.



Re: rounding_up

From
Tom Lane
Date:
Christoph Moench-Tegeder <cmt@burggraben.net> writes:
> ## Daria Shanina (vilensipkdm@gmail.com):
>> I noticed, when we parse and validate values (in particular, the int type),
>> we use the *rint* method, but unfortunately it does not work according to
>> the round rules.

> First question would be "which round rule?" as (of course) there're
> multiple to chose from.

Yeah.  Round-to-nearest-even is a well-respected rule, which is why
it's the default per IEEE 754.  I don't see a good reason for us
to switch.  Even if someone advanced an argument, it would have
to be a *mighty* convincing argument to justify breaking backwards
compatibility here.

I do find it a little unfortunate that our numeric type does it
differently than our float types.  Again though, there's a huge
compatibility argument against changing that now.  It does give
you an "out" if you really need one or the other behavior for
a particular application: you can cast to numeric or float8
before casting to int.

            regards, tom lane



Re: rounding_up

From
Daria Shanina
Date:

Hi, Christoph!

You wrote a very interesting answer. 


First question would be "which round rule?"

I mean rounding up “as at school”, but there are nuances in programming.

https://www.postgresql.org/docs/current/functions-math.html

Thanks a lot for the link to the doc!

> you set it to with fesetround() (seeman page)

To my great shame, I didn't know about fesetround(). Thanks a lot too!


Best regards,

Daria Shanina


пн, 14 апр. 2025 г. в 17:26, Tom Lane <tgl@sss.pgh.pa.us>:
Christoph Moench-Tegeder <cmt@burggraben.net> writes:
> ## Daria Shanina (vilensipkdm@gmail.com):
>> I noticed, when we parse and validate values (in particular, the int type),
>> we use the *rint* method, but unfortunately it does not work according to
>> the round rules.

> First question would be "which round rule?" as (of course) there're
> multiple to chose from.

Yeah.  Round-to-nearest-even is a well-respected rule, which is why
it's the default per IEEE 754.  I don't see a good reason for us
to switch.  Even if someone advanced an argument, it would have
to be a *mighty* convincing argument to justify breaking backwards
compatibility here.

I do find it a little unfortunate that our numeric type does it
differently than our float types.  Again though, there's a huge
compatibility argument against changing that now.  It does give
you an "out" if you really need one or the other behavior for
a particular application: you can cast to numeric or float8
before casting to int.

                        regards, tom lane


--
С уважением,
Шанина Дарья Александровна

Re: rounding_up

From
Daria Shanina
Date:

Hi, Tom!

> Round-to-nearest-even is a well-respected rule

Yes, you're convinced me! I can’t argue with IEEE 754 =) And, of course, can’t break compatibility.


Best regards,

Daria Shanina


пн, 14 апр. 2025 г. в 17:26, Tom Lane <tgl@sss.pgh.pa.us>:
Christoph Moench-Tegeder <cmt@burggraben.net> writes:
> ## Daria Shanina (vilensipkdm@gmail.com):
>> I noticed, when we parse and validate values (in particular, the int type),
>> we use the *rint* method, but unfortunately it does not work according to
>> the round rules.

> First question would be "which round rule?" as (of course) there're
> multiple to chose from.

Yeah.  Round-to-nearest-even is a well-respected rule, which is why
it's the default per IEEE 754.  I don't see a good reason for us
to switch.  Even if someone advanced an argument, it would have
to be a *mighty* convincing argument to justify breaking backwards
compatibility here.

I do find it a little unfortunate that our numeric type does it
differently than our float types.  Again though, there's a huge
compatibility argument against changing that now.  It does give
you an "out" if you really need one or the other behavior for
a particular application: you can cast to numeric or float8
before casting to int.

                        regards, tom lane


--
С уважением,
Шанина Дарья Александровна