ระบบ :: สกุลเงินและตัวสร้าง C ++

ฉันใช้ Embarcadero C++ Builder XE10 เพื่อสร้างแอปพลิเคชันที่คำนวณทางการเงินบางอย่าง

ในขณะที่พยายามใช้ประเภทข้อมูล System::Currency ฉันประสบปัญหาสองสามประการ

คำถามที่ 1: เหตุใดการคำนวณโมดูลัสจึงล้มเหลวเมื่อใช้ตัวดำเนินการ "%"

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 ซึ่งเป็นสิ่งที่ฉันคาดหวังไว้จริงๆ

คำถามที่ 2: ฉันจะทำการปัดเศษของนายธนาคารที่ถูกต้องด้วยประเภทข้อมูลสกุลเงินได้อย่างไร

ตัวอย่าง:

1.664 => 1.66
1.665 => 1.67
1.666 => 1.67

เฮอร์วิก


person Herwig    schedule 24.04.2017    source แหล่งที่มา
comment
System::Currency ไม่ได้เป็นส่วนหนึ่งของ C++ มาตรฐาน คุณมีโอกาสรวบรวมเป็น C++/CLI แทนที่จะเป็น C++ หรือไม่?   -  person Algirdas Preidžius    schedule 24.04.2017
comment
ฉันรู้. System::Currency เป็นส่วนหนึ่งของ Borland/Embarcadero Framework   -  person Herwig    schedule 24.04.2017
comment
อ้อเข้าใจแล้ว. ในกรณีนั้น - โปรดอธิบายอย่างละเอียดว่า ผลลัพธ์ที่ไม่ถูกต้อง คืออะไร เช่น. คุณคาดหวังอะไร คุณได้อะไร ทำไมคุณถึงคาดหวังให้โค้ดทำงานแตกต่างออกไป   -  person Algirdas Preidžius    schedule 24.04.2017
comment
ผลลัพธ์ถูกต้อง ดังนั้นคำถามของฉันจึงไม่ถูกกฎหมาย (คำอื่นที่แปลว่าโง่) ฉันได้รับความเข้าใจผิดจากเอาต์พุตของดีบักเกอร์ โดยที่แต่ละค่า System::Currency จะแสดงเป็นจำนวนเต็มคูณด้วย 10.000   -  person Herwig    schedule 26.04.2017


คำตอบ (1)


คำถามที่ 1: เหตุใดการคำนวณโมดูลัสจึงล้มเหลวเมื่อใช้ตัวดำเนินการ "%"

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;}

ส่วนแรกสร้างวัตถุ temp Currency ที่เริ่มต้นด้วยค่า int ของ (16650 % (10000 * 100)) = 16650 ซึ่งจะถูกคูณด้วย 10000 ถึง 166500000 โดยตัวสร้างของวัตถุ temp:

__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;}

คำถามที่ 2: ฉันจะทำการปัดเศษของนายธนาคารที่ถูกต้องด้วยประเภทข้อมูลสกุลเงินได้อย่างไร

ดูที่ฟังก์ชัน System::Round() ซึ่งใช้การปัดเศษของนายธนาคาร

หากคุณต้องการควบคุมการปัดเศษมากขึ้น ให้ใช้ฟังก์ชัน System::Math::RoundTo() หรือค้นหาฟังก์ชันการปัดเศษของบุคคลที่สาม

มีคำถามอื่นๆ อีกหลายข้อเกี่ยวกับ StackOverflow ที่เกี่ยวข้องกับการปัดเศษ Currency เช่น:

จะทำให้ประเภทสกุลเงิน Delphi ปัดเศษเหมือน Excel ตลอดเวลาได้อย่างไร

การปัดเศษสกุลเงิน

(System::Currency เป็น wrapper ของ C++ Builder สำหรับประเภท Currency ดั้งเดิมของ Delphi)

person Remy Lebeau    schedule 25.04.2017