1. المقدمة
تعتبر مكتبة Go Decimal أداة قوية للتعامل مع الكسور العشرية ذات الدقة العشرية المتغيرة في لغة Go. تتيح هذه المكتبة إجراء عمليات الجمع والطرح والضرب والقسمة دون فقدان الدقة. بالإضافة إلى ذلك، توفر وظائف مثل تسلسل/فك تسلسل قاعدة البيانات/SQL، وكذلك تسلسل/فك تسلسل JSON/XML.
2. التثبيت
لتثبيت مكتبة Go Decimal، يمكنك استخدام الأمر التالي:
go get github.com/shopspring/decimal
يرجى ملاحظة أن مكتبة Decimal تتطلب إصدار Go >=1.7.
3. الاستخدام الأساسي
لاستخدام مكتبة Decimal في برنامج Go، قم بتوريث حزمة "github.com/shopspring/decimal". فيما يلي مثال بسيط يوضح الاستخدام الأساسي:
package main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
price, err := decimal.NewFromString("136.02")
if err != nil {
panic(err)
}
quantity := decimal.NewFromInt(3)
fee, _ := decimal.NewFromString(".035")
taxRate, _ := decimal.NewFromString(".08875")
subtotal := price.Mul(quantity)
preTax := subtotal.Mul(fee).Add(decimal.NewFromFloat(1))
total := preTax.Mul(taxRate).Add(decimal.NewFromFloat(1))
fmt.Println("الإجمالي الجزئي:", subtotal)
fmt.Println("قبل الضريبة:", preTax)
fmt.Println("الضرائب:", total.Sub(preTax))
fmt.Println("الإجمالي:", total)
fmt.Println("نسبة الضريبة:", total.Sub(preTax).Div(preTax))
}
4. إنشاء متغيرات Decimal
توفر مكتبة Decimal طرقًا مختلفة لإنشاء متغيرات Decimal. فيما يلي الواجهات البرمجية المدعومة:
-
decimal.NewFromBigInt(value *big.Int, exp int32) Decimal
-
decimal.NewFromFloat(value float64) Decimal
-
decimal.NewFromFloat32(value float32) Decimal
-
decimal.NewFromFloatWithExponent(value float64, exp int32) Decimal
-
decimal.NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, error)
-
decimal.NewFromInt(value int64) Decimal
-
decimal.NewFromInt32(value int32) Decimal
-
decimal.NewFromString(value string) (Decimal, error)
-
decimal.RequireFromString(value string) Decimal
5. العمليات الحسابية
توفر مكتبة Go Decimal العديد من العمليات الحسابية التي يمكن تنفيذها على متغيرات Decimال. فيما يلي بعض العمليات المدعومة:
-
Add(d2 Decimal) Decimal
: يقوم بجمع قيمتي Decimal ويعيد النتيجة. -
Sub(d2 Decimal) Decimal
: يقوم بطرح قيمة Decimal من قيمة أخرى ويعيد النتيجة. -
Div(d2 Decimal) Decimal
: يقوم بقسمة قيمة Decimal على أخرى ويعيد النتيجة. -
DivRound(d2 Decimal, precision int32) Decimal
: يقوم بقسمة قيمة Decimal على أخرى ويعيد النتيجة بالدقة المحددة. -
Mod(d2 Decimal) Decimal
: يحسب باقي (الباقي) لقيمة Decimal عند قسمها على قيمة أخرى ويعيد النتيجة. -
Mul(d2 Decimal) Decimal
: يقوم بضرب قيمتي Decimal ويعيد النتيجة.
يمكنك استخدام هذه العمليات للقيام بعمليات الحساب الحسابية الشائعة على قيم Decimal. وفيما يلي مثال يوضح استخدام هذه العمليات:
price, _ := decimal.NewFromString("136.02")
quantity := decimal.NewFromInt(3)
subtotal := price.Mul(quantity)
tax := subtotal.Mul(decimal.NewFromFloat(0.08875))
total := subtotal.Add(tax)
fmt.Println("الإجمالي الجزئي:", subtotal)
fmt.Println("الضريبة:", tax)
fmt.Println("الإجمالي:", total)
6. عمليات التقريب
مكتبة الأرقام العشرية في Go توفر العديد من عمليات التقريب التي يمكن استخدامها لتقريب القيم العشرية إلى دقة محددة. فيما يلي بعض عمليات التقريب المتاحة:
-
Round(places int32) Decimal
: يقوم بتقريب العدد العشري إلى عدد معين من الأماكن العشرية. -
RoundBank(places int32) Decimal
: يقوم بتقريب العدد العشري باستخدام تقريب البنك إلى مكان عشري محدد. -
RoundCash(interval uint8) Decimal
: يقوم بتقريب العدد العشري إلى فاصل زمني محدد مثل 5 سنتات، 10 سنتات، 25 سنتات، 50 سنتا أو 1 دولار. -
RoundCeil(places int32) Decimal
: يقوم بتقريب العدد العشري نحو الأعلى. -
RoundDown(places int32) Decimal
: يقوم بتقريب العدد العشري نحو الصفر. -
RoundFloor(places int32) Decimal
: يقوم بتقريب العدد العشري نحو السالب. -
RoundUp(places int32) Decimal
: يقوم بتقريب العدد العشري بعيدًا عن الصفر.
6.1. التقريب
التقريب يقوم بتقريب العدد العشري إلى عدد معين من الأماكن العشرية. إذا كانت الأماكن أقل من صفر، فإنه يقوم بتقريب الجزء الصحيح إلى أقرب 10^(-الأماكن).
NewFromFloat(5.45).Round(1).String() // الناتج: "5.5"
NewFromFloat(545).Round(-1).String() // الناتج: "550"
6.2. تقريب البنك
تقريب البنك يقوم بتقريب العدد العشري إلى عدد معين من الأماكن العشرية. إذا كان الفرق بين الرقم الأخير الذي سيتم تقريبه وأقرب عددين متساوي، فإن القيمة المقربة تأخذ الرقم الزوجي.
إذا كانت الأماكن أقل من صفر، سيتم تقريب الجزء الصحيح إلى أقرب 10^(-الأماكن).
NewFromFloat(5.45).RoundBank(1).String() // الناتج: "5.4"
NewFromFloat(545).RoundBank(-1).String() // الناتج: "540"
NewFromFloat(5.46).RoundBank(1).String() // الناتج: "5.5"
NewFromFloat(546).RoundBank(-1).String() // الناتج: "550"
NewFromFloat(5.55).RoundBank(1).String() // الناتج: "5.6"
NewFromFloat(555).RoundBank(-1).String() // الناتج: "560"
6.3. تقريب النقدية
تقريب النقدية (المعروف أيضًا بالتقريب النقدي/القرشي/الأيرلندي) يقوم بتقريب العدد العشري إلى فواصل زمنية محددة. سيتم تقريب المبلغ المدفوع في عملية نقدية إلى أقرب مضاعف لوحدة العملة الصغرى. الفواصل المتاحة هي: 5، 10، 25، 50، و100. أي رقم آخر سيؤدي إلى إثارة استثناء.
5: تقريب بفاصل زمني 5 سنتات 3.43 => 3.45
10: تقريب بفاصل زمني 10 سنتات 3.45 => 3.50 (تم تقريب 5 لأعلى)
25: تقريب بفاصل زمني 25 سنتا 3.41 => 3.50
50: تقريب بفاصل زمني 50 سنتا 3.75 => 4.00
100: تقريب بفاصل زمني 100 سنت 3.50 => 4.00
6.4. تقريب نحو الأعلى
تقريب نحو الأعلى يقوم بتقريب العدد العشري نحو الإيجابية.
NewFromFloat(545).RoundCeil(-2).String() // الناتج: "600"
NewFromFloat(500).RoundCeil(-2).String() // الناتج: "500"
NewFromFloat(1.1001).RoundCeil(2).String() // الناتج: "1.11"
NewFromFloat(-1.454).RoundCeil(1).String() // الناتج: "-1.5"
6.5. تقريب نحو الصفر
تقريب نحو الصفر يقوم بتقريب العدد العشري نحو الصفر.
NewFromFloat(545).RoundDown(-2).String() // الناتج: "500"
NewFromFloat(-500).RoundDown(-2).String() // الناتج: "-500"
NewFromFloat(1.1001).RoundDown(2).String() // الناتج: "1.1"
NewFromFloat(-1.454).RoundDown(1).String() // الناتج: "-1.5"
6.6. التقريب إلى أقرب عدد صحيح
RoundFloor يقوم بتقريب العدد العشري نحو السالب.
NewFromFloat(545).RoundFloor(-2).String() // الناتج: "500"
NewFromFloat(-500).RoundFloor(-2).String() // الناتج: "-500"
NewFromFloat(1.1001).RoundFloor(2).String() // الناتج: "1.1"
NewFromFloat(-1.454).RoundFloor(1).String() // الناتج: "-1.4"
6.7. التقريب إلى أقرب عدد صحيح للأعلى
RoundUp يقوم بتقريب العدد العشري بعيدًا عن الصفر.
NewFromFloat(545).RoundUp(-2).String() // الناتج: "600"
NewFromFloat(500).RoundUp(-2).String() // الناتج: "500"
NewFromFloat(1.1001).RoundUp(2).String() // الناتج: "1.11"
NewFromFloat(-1.454).RoundUp(1).String() // الناتج: "-1.4"
7. تحويل العدد العشري إلى سلسلة نصوص
يوفر مكتبة Go Decimal أساليب لتحويل القيم العشرية إلى تمثيل سلسلة نصوص. وفيما يلي بعض الأساليب المتاحة:
-
String(): string
: تُرجع تمثيل السلسلة للعدد العشري مع نقطة عشرية ثابتة. -
StringFixed(places int32) string
: تُرجع تمثيل السلسلة المقرّبة مع عدد محدد من الأماكن العشرية. -
StringFixedBank(places int32) string
: تُرجع تمثيل السلسلة المقرّبة (بانكر) مع عدد محدد من الأماكن العشرية.
يمكنك اختيار الأسلوب المناسب وفقًا لاحتياجاتك. وفيما يلي مثال على تحويل عدد عشري إلى سلسلة نصوص:
d := decimal.NewFromFloat(5.45)
str := d.String()
fmt.Println("تمثيل السلسلة للعدد العشري:", str) // تمثيل السلسلة للعدد العشري: 5.45
// مثال StringFixed
NewFromFloat(0).StringFixed(2) // الناتج: "0.00"
NewFromFloat(0).StringFixed(0) // الناتج: "0"
NewFromFloat(5.45).StringFixed(0) // الناتج: "5"
NewFromFloat(5.45).StringFixed(1) // الناتج: "5.5"
NewFromFloat(5.45).StringFixed(2) // الناتج: "5.45"
NewFromFloat(5.45).StringFixed(3) // الناتج: "5.450"
NewFromFloat(545).StringFixed(-1) // الناتج: "550"
// مثال StringFixedBank
NewFromFloat(0).StringFixedBank(2) // الناتج: "0.00"
NewFromFloat(0).StringFixedBank(0) // الناتج: "0"
NewFromFloat(5.45).StringFixedBank(0) // الناتج: "5"
NewFromFloat(5.45).StringFixedBank(1) // الناتج: "5.4"
NewFromFloat(5.45).StringFixedBank(2) // الناتج: "5.45"
NewFromFloat(5.45).StringFixedBank(3) // الناتج: "5.450"
NewFromFloat(545).StringFixedBank(-1) // الناتج: "540"
8. الأسئلة الشائعة
س: لماذا لا يتم استخدام float64 مباشرة؟ ج: لا يمكن لـ float64 تمثيل الأرقام بدقة مثل 0.1، مما يمكن أن يؤدي إلى أخطاء صغيرة. في حالات الحسابات المالية، قد تتراكم هذه الأخطاء مع مرور الوقت وتسبب مشاكل كبيرة.
س: لماذا لا يتم استخدام big.Rat مباشرة؟ ج: على الرغم من أن big.Rat يمكن أن يمثل الأعداد الكسرية، إلا أنه غير مناسب لتمثيل العملة. تعتبر الأعداد العشرية أفضل للحسابات المالية لأنها يمكن أن تمثل بدقة الكسور العشرية دون فقدان الدقة.
س: لماذا لا يكون واجهة برمجة التطبيقات مشابهة لـ big.Int؟ ج: تعطي واجهة برمجة التطبيقات (API) لمكتبة Decimal الأولوية لسهولة الاستخدام والصحة على حساب الأداء. بينما تقلل واجهة big.Int من تخصيص الذاكرة لأسباب الأداء، فإن ذلك قد يؤدي إلى كود معقد ومعرض للأخطاء. تم تصميم واجهة مكتبة Decimal لتكون بسيطة وسهلة الفهم.