qRound() in Qt
-
-
std::round()
manages floating point errors better (should also be thread safe but need to double checkfenv_t
being actually thread local).Normally the only reason to use
q*
functions overstd::*
functions is indeed thread safety. -
@VRonin
Just so I can check I do understand, the only issue for "thread safety" for this would be if another thread were in the process of alteringfenv_t
(which would be pretty unusual), right?@JonB some functions (the most famous being
std::rand
) might trigger race conditions if called at the same time from 2 different threads (in the example because the random seed is shared across multiple threads).I checked and the float environment is thread local so safe to use
std::round
overqRound
-
-
@JonB some functions (the most famous being
std::rand
) might trigger race conditions if called at the same time from 2 different threads (in the example because the random seed is shared across multiple threads).I checked and the float environment is thread local so safe to use
std::round
overqRound
-
@VRonin It seems the qRound() and std::round() will output different values for some same arguments. Right?
-
@diverger said in qRound() in Qt:
Right?
Unless you go to border cases with stuff like 99.55555555555 they should give you the same answer -
@VRonin Please try the code below:
double b = -0.5; qDebug() << std::round(b); qDebug() << qRound(b);
Qt 5.10.1 + VS2015, give me:
-1 0
Whoever downvoted @VRonin's answer, please don't (unless it was a mis-click!), as his answer was correct.
@diverger
Bothstd::round()
andqRound()
round to an integer. However, they may not necessarily round to the same integer in the case ofX.5
because there is no "correct"/"unambiguous" answer in that case. The implementation might round either up or down, and might differ in which way they roundX.5
versus-X.5
.So you appear to have found different behaviour, at least in the case of
-0.5
. Both results are "correct". If you really care in such a case, you may find you prefer the behaviour of one over the other, in which case use that one, or adjust your calling code as desired. -
Whoever downvoted @VRonin's answer, please don't (unless it was a mis-click!), as his answer was correct.
@diverger
Bothstd::round()
andqRound()
round to an integer. However, they may not necessarily round to the same integer in the case ofX.5
because there is no "correct"/"unambiguous" answer in that case. The implementation might round either up or down, and might differ in which way they roundX.5
versus-X.5
.So you appear to have found different behaviour, at least in the case of
-0.5
. Both results are "correct". If you really care in such a case, you may find you prefer the behaviour of one over the other, in which case use that one, or adjust your calling code as desired.@JonB I don't mean qRound() is wrong in his behavior. And I know also there are some many rounding methods when x.5 is given to these function. I just want to know more about the function, what's is main purpose to add it to Qt. As Qt only give a simple word in it's doc. When I found the qRound() function in the doc, I think it's just as the doc say "round -to-nearest", but finally I found it will give me different result from some others. And at last, I found the function I need is actually the more recent "rint()".
So, I just want know more about this function.
-
qRound()
:
https://code.woboq.org/qt5/qtbase/src/corelib/global/qglobal.h.html#_Z6qRounddSo if
decimalPart(abs(d))
< 0.5 rounds down otherwise round up -
See also https://stackoverflow.com/questions/47156806/stdnearbyint-vs-stdround-in-c11 for all the complexities/variants etc. of the
std::
equivalents. -
Whoever downvoted @VRonin's answer, please don't (unless it was a mis-click!), as his answer was correct.
@diverger
Bothstd::round()
andqRound()
round to an integer. However, they may not necessarily round to the same integer in the case ofX.5
because there is no "correct"/"unambiguous" answer in that case. The implementation might round either up or down, and might differ in which way they roundX.5
versus-X.5
.So you appear to have found different behaviour, at least in the case of
-0.5
. Both results are "correct". If you really care in such a case, you may find you prefer the behaviour of one over the other, in which case use that one, or adjust your calling code as desired.@JonB said in qRound() in Qt:
However, they may not necessarily round to the same integer in the case of X.5 because there is no "correct"/"unambiguous" answer in that case. The implementation might round either up or down, and might differ in which way they round X.5 versus -X.5.
As Luca pointed out, this is "controllable" (albeit not as good as we'd like) through the floating point environment - i.e. whether rounding should be up, down or to nearest. From my experience, by default round to nearest is preferred, however this is not set in stone.
PS. The above is for
std::round
, while Qt'sqRound
implementation is rather suspicious. It's not aware of the floating point environment, it basically goes like this:int qRound(double x) { return x + 0.5; // Will round to nearest, but there's no control over the behavior and one works if you want integers, it can't be used to round fp type to some predefined precision. }
-
@diverger said in qRound() in Qt:
Right?
Unless you go to border cases with stuff like 99.55555555555 they should give you the same answer@VRonin said in qRound() in Qt:
Unless you go to border cases with stuff like 99.55555555555 they should give you the same answer
While we're being all very precise about this rounding issue ( :) ), I meant to pick you up on this. What is "border case" about this? It's unambiguously 100! Perhaps you had mind "rounding to n - 1 decimal places" here?
-
@VRonin said in qRound() in Qt:
Unless you go to border cases with stuff like 99.55555555555 they should give you the same answer
While we're being all very precise about this rounding issue ( :) ), I meant to pick you up on this. What is "border case" about this? It's unambiguously 100! Perhaps you had mind "rounding to n - 1 decimal places" here?
-
@JonB said in qRound() in Qt:
It's unambiguously 100!
Yep, sorry I meant 99.49999999999 but even that is unabiguous
@VRonin
Ah, OK, just checking I wasn't aware of something.Actually your
.49999999999
kind of, in principle holds, and is worthy of mention, not as "ambiguous" but as "border case", insofar as it warns of the limits of floating point precision in an fp implementation.It would probably require a few more decimal places in a
double
, but users should be aware that all fp values are indeed approximate, which can show up in such "edge cases". Thus it is not necessarily the case that:99.49999999999999999999999 + 0.5 == 99.99999999999999999999999
In some implementations/hardware environments it might equal that, but in others it might equal, say,
100.0
.And this is significant, because in what we have been discussing even with the same rounding algorithm the result of the integer round might be
99
in one implementation and100
in another as a result of this precision issue. -
@VRonin
Ah, OK, just checking I wasn't aware of something.Actually your
.49999999999
kind of, in principle holds, and is worthy of mention, not as "ambiguous" but as "border case", insofar as it warns of the limits of floating point precision in an fp implementation.It would probably require a few more decimal places in a
double
, but users should be aware that all fp values are indeed approximate, which can show up in such "edge cases". Thus it is not necessarily the case that:99.49999999999999999999999 + 0.5 == 99.99999999999999999999999
In some implementations/hardware environments it might equal that, but in others it might equal, say,
100.0
.And this is significant, because in what we have been discussing even with the same rounding algorithm the result of the integer round might be
99
in one implementation and100
in another as a result of this precision issue.@JonB I'm not qualified to give opionons on this, I'll just ask @kshegunov's help.
I thought error of double was always in defect so, since 0.5 is perfectly represented in double, the double representation of99.49999999999999999999999 + 0.5
will always be<= 99.99999999999999999999999
-
@JonB I'm not qualified to give opionons on this, I'll just ask @kshegunov's help.
I thought error of double was always in defect so, since 0.5 is perfectly represented in double, the double representation of99.49999999999999999999999 + 0.5
will always be<= 99.99999999999999999999999
@VRonin said in qRound() in Qt:
I thought error of double was always in defect
No not necessarily. Depends on the number you are trying to represent. Consider
2/3
in decimal floating point (opposed to the binary used in computers, just for simplicity) as an example, that'd give you0.6(6..)7
as the last digit would be rounded up if you use round-to-nearest. Same consideration applies for binary digits. The usual floating point's fraction is represented, as is known (ignoring all the normalizations and such), as the sum:Number = Sum(i_k / 2^k)
Where
i_k
is the k-th binary digit (either0
or1
) and2^k
is the k-th power of 2. Same as with the decimal case, except the base is2
. Then the question becomes whether the after-the-last representable digit is rounded up or down. That's why one says thatsqrt
is accurate to 0.5 epsilons, as the actual calculation is performed in extended precision and then the result is rounded to the representable double type. This means the error from rounding is bound by half an epsilon - i.e. whether it was rounded up or down.