mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Fix half-up, half-down, and banker's rounding for negative numbers.
We need to compare the magnitudes of the remainder and the denominator in order to round negative numbers correctly. Note that while gnc_numeric is constrained to a positive denominator the C++ rounding functions cannot assume that constraint in all cases. Combined with the previous commit, this fixes Bug 796949 - Incorrect conversion of 0,01 USD to EUR
This commit is contained in:
parent
536606a89c
commit
61cd7999f3
@ -23,6 +23,7 @@
|
||||
#ifndef __GNC_RATIONAL_ROUNDING_HPP__
|
||||
#define __GNC_RATIONAL_ROUNDING_HPP__
|
||||
#include "gnc-numeric.h"
|
||||
#include "gnc-int128.hpp"
|
||||
|
||||
enum class RoundType
|
||||
{
|
||||
@ -105,7 +106,18 @@ round(T num, T den, T rem, RT2T<RoundType::half_down>)
|
||||
{
|
||||
if (rem == 0)
|
||||
return num;
|
||||
if (rem * 2 > den)
|
||||
if (std::abs(rem * 2) > std::abs(den))
|
||||
return num + (num < 0 ? -1 : 1);
|
||||
return num;
|
||||
}
|
||||
|
||||
template <> inline GncInt128
|
||||
round<GncInt128>(GncInt128 num, GncInt128 den, GncInt128 rem,
|
||||
RT2T<RoundType::half_down>)
|
||||
{
|
||||
if (rem == 0)
|
||||
return num;
|
||||
if (rem.abs() * 2 > den.abs())
|
||||
return num + (num < 0 ? -1 : 1);
|
||||
return num;
|
||||
}
|
||||
@ -115,7 +127,18 @@ round(T num, T den, T rem, RT2T<RoundType::half_up>)
|
||||
{
|
||||
if (rem == 0)
|
||||
return num;
|
||||
if (rem * 2 >= den)
|
||||
if (std::abs(rem) * 2 >= std::abs(den))
|
||||
return num + (num < 0 ? -1 : 1);
|
||||
return num;
|
||||
}
|
||||
|
||||
template <> inline GncInt128
|
||||
round<GncInt128>(GncInt128 num, GncInt128 den, GncInt128 rem,
|
||||
RT2T<RoundType::half_up>)
|
||||
{
|
||||
if (rem == 0)
|
||||
return num;
|
||||
if (rem.abs() * 2 >= den.abs())
|
||||
return num + (num < 0 ? -1 : 1);
|
||||
return num;
|
||||
}
|
||||
@ -125,9 +148,21 @@ round(T num, T den, T rem, RT2T<RoundType::bankers>)
|
||||
{
|
||||
if (rem == 0)
|
||||
return num;
|
||||
if (rem * 2 > den || (rem * 2 == den && num % 2))
|
||||
if (std::abs(rem * 2) > std::abs(den) ||
|
||||
(std::abs(rem * 2) == std::abs(den) && num % 2))
|
||||
return num += (num < 0 ? -1 : 1);
|
||||
return num;
|
||||
}
|
||||
|
||||
template<> inline GncInt128
|
||||
round<GncInt128>(GncInt128 num, GncInt128 den, GncInt128 rem,
|
||||
RT2T<RoundType::bankers>)
|
||||
{
|
||||
if (rem == 0)
|
||||
return num;
|
||||
if (rem.abs() * 2 > den.abs() ||
|
||||
(rem.abs() * 2 == den.abs() && num % 2))
|
||||
return num += (num < 0 ? -1 : 1);
|
||||
return num;
|
||||
}
|
||||
#endif //__GNC_RATIONAL_ROUNDING_HPP__
|
||||
|
Loading…
Reference in New Issue
Block a user