1. مقدمہ

Go ڈیسیمل لائبریری Go زبان میں اختیاری پیمانہ پر مبنی ہونے والی فکسڈ پوائنٹ ڈیسیمل کو ہینڈل کرنے کے لئے ایک طاقتور ٹول ہے۔ یہ اضافہ، تفریق، ضرب، اور تقسیم کی عملیات کی اجازت دیتا ہے بغیر حساسیت کھو دینے والی۔ علاوہ ازیں، یہ ڈیٹابیس/SQL سیریلائزیشن/ڈی سیریلائزیشن، ساتھ ہی JSON/XML سیریلائزیشن/ڈی سیریلائزیشن جیسی کارکردگی فراہم کرتا ہے۔

2. نصبیت

Go ڈیسیمل لائبریری کو نصب کرنے کے لئے، آپ نیچے دیے گئے کمانڈ کا استعمال کرسکتے ہیں:

go get github.com/shopspring/decimal

براہ کرم نوٹ کریں کہ ڈیسیمل لائبریری کو Go ورژن >=1.7 کی ضرورت ہوتی ہے۔

3. بنیادی استعمال

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:", subtotal)                  // Subtotal: 408.06
	fmt.Println("Pre-tax:", preTax)                     // Pre-tax: 422.3421
	fmt.Println("Taxes:", total.Sub(preTax))            // Taxes: 37.482861375
	fmt.Println("Total:", total)                         // Total: 459.824961375
	fmt.Println("Tax rate:", total.Sub(preTax).Div(preTax)) // Tax rate: 0.08875
}

4. ڈیسیمل متغیرات بنانا

ڈیسیمل لائبریری مختلف تراکیب فراہم کرتی ہے تاکہ ڈیسیمل متغیرات بنائے جا سکیں۔ ذیل میں معتمد ایپلیکیشن پروگرامنگ انٹرفیس کی تفصیلات دی گئی ہیں:

  • 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 ڈیسیمل لائبریری مختلف حسابی عملیات فراہم کرتی ہے جو ڈیسیمل متغیرات پر کیے جا سکتے ہیں۔ یہاں کچھ معتمد عملیات دی گئی ہیں:

  • Add(d2 Decimal) Decimal: دو ڈیسیمل قیمتیں جمع کرتا ہے اور نتیجہ واپس کرتا ہے۔
  • Sub(d2 Decimal) Decimal: ایک ڈیسیمل قیمت سے دوسرے کو منفی کرتا ہے اور نتیجہ واپس کرتا ہے۔
  • Div(d2 Decimal) Decimal: ایک ڈیسیمل قیمت کو دوسرے سے تقسیم کرتا ہے اور نتیجہ واپس کرتا ہے۔
  • DivRound(d2 Decimal, precision int32) Decimal: ایک ڈیسیمل قیمت کو دوسرے سے تقسیم کرتا ہے اور مخصوص درستگی کے ساتھ نتیجہ واپس کرتا ہے۔
  • Mod(d2 Decimal) Decimal: ایک ڈیسیمل قیمت کو دوسرے سے تقسیم کرنے کا بچا ہوا حصہ حاصل کرتا ہے اور نتیجہ واپس کرتا ہے۔
  • Mul(d2 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:", subtotal) // Subtotal: 408.06
fmt.Println("Tax:", tax)           // Tax: 36.244985
fmt.Println("Total:", total)       // Total: 444.304985

اس مثال میں ہم Mul() میتھڈ کا استعمال کرکے subtotal کا حساب کرتے ہیں جو price اور quantity کو ضرب دیکر ہوتا ہے۔ پھر ہم tax حاصل کرتے ہیں جو subtotal کو ٹیکس کی شرح سے ضرب دیکر حاصل ہوتا ہے۔ آخر میں، ہم Add() میتھڈ کا استعمال کرکے subtotal اور tax کو جمع کرکے total کا حساب کرتے ہیں۔

6. راؤنڈنگ آپریشنز

Go ڈیسیمل لائبریری مخصوص راؤنڈنگ آپریشنز فراہم کرتی ہے جو ڈیسیمل اقدار کو مخصوص پریسیژن تک راؤنڈ کرنے کے لئے استعمال کیا جا سکتا ہے۔ یہاں کچھ دستیاب راؤنڈنگ آپریشنز ہیں:

  • Round(places int32) Decimal: ڈیسیمل کو مخصوص تعداد کے ڈیسیمل چھوٹ کرتا ہے۔
  • RoundBank(places int32) Decimal: ڈیسیمل کو بینکر کی راؤنڈنگ کا استعمال کرکے مخصوص تعداد کے ڈیسیمل تک راؤنڈ کرتا ہے۔
  • RoundCash(interval uint8) Decimal: ڈیسیمل کو مخصوص وقفے تک راؤنڈ کرتا ہے، مثلاً 5 سینٹس، 10 سینٹس، 25 سینٹس، 50 سینٹس یا ایک ڈالر۔
  • RoundCeil(places int32) Decimal: ڈیسیمل کو مثبت نہایت تک راؤنڈ کرتا ہے۔
  • RoundDown(places int32) Decimal: ڈیسیمل کو صفر کی سمت میں راؤنڈ کرتا ہے۔
  • RoundFloor(places int32) Decimal: ڈیسیمل کو منفی نہایت تک راؤنڈ کرتا ہے۔
  • RoundUp(places int32) Decimal: ڈیسیمل کو صفر سے دور راؤنڈ کرتا ہے۔

6.1. Round

Round ڈیسیمل کو مخصوص تعداد کے ڈیسیمل چھوٹ کرتا ہے۔ اگر places < 0 ہو تو یہ عدد صحیح حصے کو نزدیکی 10^(-places) تک راؤنڈ کرتا ہے۔

NewFromFloat(5.45).Round(1).String() // Output: "5.5"
NewFromFloat(545).Round(-1).String() // Output: "550"

6.2. RoundBank

RoundBank ڈیسیمل کو مخصوص تعداد کے ڈیسیمل تک راؤنڈ کرتا ہے۔ اگر آخری ڈیجٹ کا فرق نزدیک ترین دو عددوں کے درمیان برابر ہو، تو راؤنڈ کردہ قدر زوج عدد لی جائے گی۔

اگر places < 0 ہو تو، عدد صحیح کو نزدیکی 10^(-places) تک راؤنڈ کیا جائے گا۔

NewFromFloat(5.45).RoundBank(1).String() // Output: "5.4"
NewFromFloat(545).RoundBank(-1).String() // Output: "540"
NewFromFloat(5.46).RoundBank(1).String() // Output: "5.5"
NewFromFloat(546).RoundBank(-1).String() // Output: "550"
NewFromFloat(5.55).RoundBank(1).String() // Output: "5.6"
NewFromFloat(555).RoundBank(-1).String() // Output: "560"

6.3. RoundCash

RoundCash (یا کیش/پینی/آئرش راؤنڈنگ کے نام سے بھی جانا جاتا ہے) ڈیسیمل کو مخصوص وقفوں تک راؤنڈ کرتا ہے۔ ایک کیش ٹرانزیکشن کی ادائیگی کا رقبہ نزدیکی سب سے چھوٹی کرنسی یونٹ کی قریبی گنا ہوتا ہے۔ دستیاب وقفے ہیں: 5، 10، 25، 50، اور 100۔ کسی بھی دوسرے عدد کی صورت میں استثناء آئے گا۔

  5:   3.43 => 3.45
 10:   3.45 => 3.50 (5 کو اوپر راؤنڈ کیا گیا ہے)
 25:   3.41 => 3.50
 50:   3.75 => 4.00
100:   3.50 => 4.00

6.4. RoundCeil

RoundCeil ڈیسیمل کو مثبت نہایت تک راؤنڈ کرتا ہے۔

NewFromFloat(545).RoundCeil(-2).String()   // Output: "600"
NewFromFloat(500).RoundCeil(-2).String()   // Output: "500"
NewFromFloat(1.1001).RoundCeil(2).String() // Output: "1.11"
NewFromFloat(-1.454).RoundCeil(1).String() // Output: "-1.5"

6.5. RoundDown

RoundDown ڈیسیمل کو صفر کی سمت میں راؤنڈ کرتا ہے۔

NewFromFloat(545).RoundDown(-2).String()   // Output: "500"
NewFromFloat(-500).RoundDown(-2).String()   // Output: "-500"
NewFromFloat(1.1001).RoundDown(2).String() // Output: "1.1"
NewFromFloat(-1.454).RoundDown(1).String() // Output: "-1.5"

6.6. RoundFloor

RoundFloor ڈیسیمل کو منفی بےانتہا جانب گول کرتا ہے۔

NewFromFloat(545).RoundFloor(-2).String()   // Output: "500"
NewFromFloat(-500).RoundFloor(-2).String()   // Output: "-500"
NewFromFloat(1.1001).RoundFloor(2).String() // Output: "1.1"
NewFromFloat(-1.454).RoundFloor(1).String() // Output: "-1.4"

6.7. RoundUp

RoundUp ڈیسیمل کو صفر سے دور گول کرتا ہے۔

NewFromFloat(545).RoundUp(-2).String()   // Output: "600"
NewFromFloat(500).RoundUp(-2).String()   // Output: "500"
NewFromFloat(1.1001).RoundUp(2).String() // Output: "1.11"
NewFromFloat(-1.454).RoundUp(1).String() // Output: "-1.4"

7. ڈیسیمل ٹائپ کو سٹرنگ میں تبدیل کریں

Go ڈیسیمل لائبریری میں ڈیسیمل قیمتوں کو سٹرنگ تشکیل دینے کے لئے تراکیب فراہم کرتی ہے۔ یہاں دی گئی ہیں چند دستیاب تراکیب:

  • 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) // Output: "0.00"
NewFromFloat(0).StringFixed(0) // Output: "0"
NewFromFloat(5.45).StringFixed(0) // Output: "5"
NewFromFloat(5.45).StringFixed(1) // Output: "5.5"
NewFromFloat(5.45).StringFixed(2) // Output: "5.45"
NewFromFloat(5.45).StringFixed(3) // Output: "5.450"
NewFromFloat(545).StringFixed(-1) // Output: "550"

// StringFixedBank مثال
NewFromFloat(0).StringFixedBank(2) // Output: "0.00"
NewFromFloat(0).StringFixedBank(0) // Output: "0"
NewFromFloat(5.45).StringFixedBank(0) // Output: "5"
NewFromFloat(5.45).StringFixedBank(1) // Output: "5.4"
NewFromFloat(5.45).StringFixedBank(2) // Output: "5.45"
NewFromFloat(5.45).StringFixedBank(3) // Output: "5.450"
NewFromFloat(545).StringFixedBank(-1) // Output: "540"

8. عام سوالات

س: مستقیم float64 کیوں نہیں استعمال کرنا؟ ج: float64 صرف 0.1 جیسے اعشاریہ کو درست نمائندگی نہیں دے سکتا، جو چھوٹی خطا کے لئے منتقل ہو سکتا ہے۔ فنانشل حساب رکنیوں کے معاملات میں، یہ خطا وقت کے ساتھ جمع ہو کر بڑے مسائل کا باعث بن سکتی ہے۔

س: مستقیم big.Rat کیوں نہیں استعمال کرنا؟ ج: بیشک big.Rat نسبتی اعداد کو نمائندگی دینے کے قابل ہے، لیکن یہ سکہ کی نمائندگی کے لئے مناسب نہیں ہے۔ ڈیسیمل نمبر فنانشل حسابات کے لئے بہتر ہوتے ہیں کیونکہ یہ درستگی کے ساتھ اعشاریہ کی فرضیات کو داغ بیغیرت پر رکھ سکتے ہیں۔

س: کیوں ڈیسیمل لائبریری کا API big.Int کے مشابہ نہیں ہے؟ ج: ڈیسیمل لائبریری کا API استعمالیت اور صحت کو فوائد دینے میں ترجیح دیتا ہے۔ جبکہ big.Int کا API فوریز کیلئے حافظہ کے تخصیصات کم کرتا ہے، یہ فنانشل حسابات کے لئے پیچیدہ اور خطرناک کوڈ کا باعث بن سکتا ہے۔ ڈیسیمل لائبریری کا API سادہ اور سمجھنے میں آسان ہونے کے لئے ڈیزائن کیا گیا ہے۔