我正在使用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;
编辑:我完全被调试器的输出所愚弄了 System :: Currency的值显示在其整数表示中 到10.000。
我真正希望看到的是:
Rest = (TaxValue * 10000) % 100;
==>现在休息是50,这正是我的预期。
Q2:如何使用Curreny数据类型对正确的银行家进行四舍五入?
示例:
1.664 => 1.66
1.665 => 1.67
1.666 => 1.67
赫维希
答案 0 :(得分:1)
Q1:使用“%”运算符时,为什么模数计算失败?
System::Currency
以4位小数的精度运算。您的示例需要2位精度。
System::Currency
通过在内部将输入值乘以10000
然后使用整数数学而不是浮点数学来操纵值来保持其精度而不会舍入错误。
使用TaxValue
初始化1.665
时,其内部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;}
:
System::Round()
Q2:如何使用Curreny数据类型对正确的银行家进行舍入?
查看使用银行家舍入的System::Math::RoundTo()
函数。
如果您想要更好地控制舍入,请使用Currency
功能,或找到第三方舍入功能。
StackOverflow还有其他一些问题涉及System::Currency
舍入,例如:
How to get Delphi Currency Type to Round like Excel all the time?
(Currency
是C ++ Builder的Delphi本地git show -s
类型的包装器。)