System::Currency 和 C++ 生成器
System::Currency and C++ Builder
我正在使用 Embarcadero C++ Builder XE10 构建一个执行一些货币计算的应用程序。
在尝试使用 System::Currency 数据类型时,我遇到了一些问题。
Q1:为什么使用“%”运算符计算模数会失败?
System::Currency TaxValue = 1.665;
System::Currency Rest = 0;
// Correct result: Rest will be 0.005 when converted to double
Rest = TaxValue - ( TaxValue / 100 * 100 );
// Incorrect result: Rest is the same as TaxValue
Rest = TaxValue % 100;
Edit: I have been totally fooled by the debugger's output where the
System::Currency's value is shown in its integer represention multiplied
by 10.000.
What I really expected to see was:
Rest = (TaxValue * 10000) % 100;
==> Now Rest is 50, which is exactly what I expected.
问题 2:如何使用 Curreny 数据类型进行正确的银行四舍五入?
示例:
1.664 => 1.66
1.665 => 1.67
1.666 => 1.67
赫维格
Q1: Why does the calculation of the modulus fail when using the "%" operator?
System::Currency
以小数点后 4 位的精度进行运算。您的示例需要 2 位精度。
System::Currency
通过在内部将输入值乘以 10000
然后使用整数数学而不是浮点数学来处理值来保持其精度而没有舍入错误。
当您使用 1.665
初始化 TaxValue
时,其内部 Val
成员(即 __int64
)被设置为 (1.665 * 10000) = 16650
。这是构造函数的样子:
__fastcall Currency(double val) {Val = _roundToInt64(10000 * val);}
然后执行 TaxValue % 100
时,%
运算符是这样实现的:
Currency __fastcall operator %(int rhs) const
{return Currency(static_cast<int>(Val % (10000 * (__int64)rhs))) / 10000;}
第一部分创建一个临时 Currency
对象,该对象使用 int
值 (16650 % (10000 * 100)) = 16650
初始化,乘以 10000
到 166500000
通过临时对象的构造函数:
__fastcall Currency(int val) {Val = 10000*(__int64)val;}
第二部分然后将温度除以 10000
。 /
运算符是这样实现的:
Currency& __fastcall operator /=(const Currency& rhs)
{Val *= 10000; Val /= rhs.Val; return *this;}
Currency __fastcall operator /(int rhs) const
{Currency tmp(*this); return tmp /= Currency(rhs);}
从而生成最终的 Currency
对象,其 Val
已设置为 (166500000 * 10000) / (10000 * 10000) = 16650
。
当最后的 Currency
被分配给 Rest
并转换为 double
时,该值除以 10000
,从而产生 1.665
:
__fastcall operator double() const {return ((double)Val) / 10000;}
Q2: How can I do a correct banker's rounding with the Curreny data type?
看看 System::Round()
函数,它使用银行四舍五入。
如果您想更好地控制舍入,请使用 System::Math::RoundTo()
函数,或查找第 3 方舍入函数。
Whosebug 上还有其他几个问题涉及 Currency
舍入,例如:
How to get Delphi Currency Type to Round like Excel all the time?
rounding a currency
(System::Currency
是 C++Builder 对 Delphi 的原生 Currency
类型的包装器)。
我正在使用 Embarcadero C++ Builder XE10 构建一个执行一些货币计算的应用程序。
在尝试使用 System::Currency 数据类型时,我遇到了一些问题。
Q1:为什么使用“%”运算符计算模数会失败?
System::Currency TaxValue = 1.665;
System::Currency Rest = 0;
// Correct result: Rest will be 0.005 when converted to double
Rest = TaxValue - ( TaxValue / 100 * 100 );
// Incorrect result: Rest is the same as TaxValue
Rest = TaxValue % 100;
Edit: I have been totally fooled by the debugger's output where the System::Currency's value is shown in its integer represention multiplied by 10.000.
What I really expected to see was:
Rest = (TaxValue * 10000) % 100;
==> Now Rest is 50, which is exactly what I expected.
问题 2:如何使用 Curreny 数据类型进行正确的银行四舍五入?
示例:
1.664 => 1.66
1.665 => 1.67
1.666 => 1.67
赫维格
Q1: Why does the calculation of the modulus fail when using the "%" operator?
System::Currency
以小数点后 4 位的精度进行运算。您的示例需要 2 位精度。
System::Currency
通过在内部将输入值乘以 10000
然后使用整数数学而不是浮点数学来处理值来保持其精度而没有舍入错误。
当您使用 1.665
初始化 TaxValue
时,其内部 Val
成员(即 __int64
)被设置为 (1.665 * 10000) = 16650
。这是构造函数的样子:
__fastcall Currency(double val) {Val = _roundToInt64(10000 * val);}
然后执行 TaxValue % 100
时,%
运算符是这样实现的:
Currency __fastcall operator %(int rhs) const
{return Currency(static_cast<int>(Val % (10000 * (__int64)rhs))) / 10000;}
第一部分创建一个临时 Currency
对象,该对象使用 int
值 (16650 % (10000 * 100)) = 16650
初始化,乘以 10000
到 166500000
通过临时对象的构造函数:
__fastcall Currency(int val) {Val = 10000*(__int64)val;}
第二部分然后将温度除以 10000
。 /
运算符是这样实现的:
Currency& __fastcall operator /=(const Currency& rhs)
{Val *= 10000; Val /= rhs.Val; return *this;}
Currency __fastcall operator /(int rhs) const
{Currency tmp(*this); return tmp /= Currency(rhs);}
从而生成最终的 Currency
对象,其 Val
已设置为 (166500000 * 10000) / (10000 * 10000) = 16650
。
当最后的 Currency
被分配给 Rest
并转换为 double
时,该值除以 10000
,从而产生 1.665
:
__fastcall operator double() const {return ((double)Val) / 10000;}
Q2: How can I do a correct banker's rounding with the Curreny data type?
看看 System::Round()
函数,它使用银行四舍五入。
如果您想更好地控制舍入,请使用 System::Math::RoundTo()
函数,或查找第 3 方舍入函数。
Whosebug 上还有其他几个问题涉及 Currency
舍入,例如:
How to get Delphi Currency Type to Round like Excel all the time?
rounding a currency
(System::Currency
是 C++Builder 对 Delphi 的原生 Currency
类型的包装器)。