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 初始化,乘以 10000166500000通过临时对象的构造函数:

__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 类型的包装器)。