decimal --- حساب دهدهی ممیز ثابت و ممیز شناور¶
کد منبع: Lib/decimal.py
ماژول decimal پشتیبانی از محاسبات ممیز شناور اعشاری سریع و با گرد کردن صحیح را فراهم میکند. این ماژول چندین مزیت نسبت به نوع داده float دارد:
Decimal «بر اساس یک مدل ممیز شناور است که با در نظر گرفتن انسانها طراحی شده و لزوماً دارای یک اصل راهنمای برتر است -- رایانهها باید حسابی فراهم کنند که به همان شیوهای کار کند که حسابی که مردم در مدرسه میآموزند، کار میکند.» -- گزیدهای از مشخصات حساب اعشاری.
اعداد دهدهی را میتوان بهصورت دقیق بازنمایی کرد. در مقابل، اعدادی مانند
1.1و2.2بازنمایی دقیقی در ممیز شناور دودویی ندارند. کاربران نهایی معمولاً انتظار ندارند1.1 + 2.2بهصورت3.3000000000000003نمایش داده شود، همانگونه که در ممیز شناور دودویی رخ میدهد.این دقت در محاسبات حسابی نیز برقرار است. در ممیز شناور اعشاری،
0.1 + 0.1 + 0.1 - 0.3دقیقاً برابر با صفر است. در ممیز شناور دودویی، نتیجه5.5511151231257827e-017است. هرچند به صفر نزدیک است، اما این تفاوتها مانع از بررسی برابری قابلاعتماد میشوند و ممکن است انباشته شوند. به همین دلیل، ممیز شناور اعشاری در برنامههای حسابداری که دارای ناورداهای برابری دقیق هستند، ترجیح داده میشود.ماژول decimal مفهوم ارقام معنادار را در بر میگیرد، بهطوریکه
1.30 + 1.20برابر2.50است. صفر پایانی برای نشان دادن معناداری حفظ میشود. این نمایش مرسوم برای کاربردهای مالی است. برای ضرب، روش «کتاب درسی» از تمام ارقام عوامل ضرب استفاده میکند. برای مثال،1.3 * 1.2مقدار1.56را میدهد، در حالی که1.30 * 1.20مقدار1.5600را میدهد.برخلاف ممیز شناور دودویی مبتنی بر سختافزار، ماژول decimal دارای دقت قابل تغییر توسط کاربر (با پیشفرض ۲۸ رقم اعشار) است که میتواند به هر اندازهای که برای یک مسئله مشخص لازم باشد، بزرگ باشد:
>>> from decimal import * >>> getcontext().prec = 6 >>> Decimal(1) / Decimal(7) Decimal('0.142857') >>> getcontext().prec = 28 >>> Decimal(1) / Decimal(7) Decimal('0.1428571428571428571428571429')
هر دو نوع ممیز شناور دودویی و اعشاری بر اساس استانداردهای منتشرشده پیادهسازی شدهاند. در حالی که نوع float توکار تنها بخش محدودی از قابلیتهای خود را در اختیار میگذارد، ماژول decimal تمام بخشهای مورد نیاز استاندارد را در اختیار میگذارد. در صورت نیاز، برنامهنویس کنترل کاملی بر گرد کردن و مدیریت سیگنال دارد. این شامل گزینهای برای اعمال حساب دقیق با استفاده از استثناها جهت مسدود کردن هرگونه عملیات غیردقیق است.
ماژول decimal طراحی شده است تا «بدون جانبداری، هم از حساب اعشاری دقیق و بدون گرد کردن (که گاهی حساب ممیز ثابت نامیده میشود) و هم از حساب ممیز شناور گردشده» پشتیبانی کند. — گزیدهای از مشخصات حساب اعشاری.
طراحی ماژول بر سه مفهوم متمرکز است: عدد اعشاری، زمینه محاسبات، و سیگنالها.
یک عدد دهدهی تغییرناپذیر است. این عدد دارای علامت، ارقام ضریب و توان است. برای حفظ معناداری، صفرهای انتهایی از ارقام ضریب حذف نمیشوند. اعداد دهدهی همچنین شامل مقادیر خاصی مانند Infinity، -Infinity و NaN هستند. این استاندارد همچنین -0 را از +0 متمایز میکند.
زمینهی محاسبات، محیطی است که دقت، قواعد گرد کردن، محدودیتهای توانها، پرچمهای نشاندهندهی نتایج عملیات و فعالسازهای تله را مشخص میکند؛ فعالسازهای تله تعیین میکنند که آیا سیگنالها بهعنوان استثنا در نظر گرفته میشوند یا خیر. گزینههای گرد کردن شامل ROUND_CEILING، ROUND_DOWN، ROUND_FLOOR، ROUND_HALF_DOWN، ROUND_HALF_EVEN، ROUND_HALF_UP، ROUND_UP و ROUND_05UP هستند.
سیگنالها گروههایی از شرایط استثنایی هستند که در طول محاسبات رخ میدهند. بسته به نیازهای برنامه، ممکن است سیگنالها نادیده گرفته شوند، بهعنوان اطلاعرسانی در نظر گرفته شوند، یا بهعنوان استثنا مدیریت شوند. سیگنالهای ماژول decimal عبارتند از: Clamped، InvalidOperation، DivisionByZero، Inexact، Rounded، Subnormal، Overflow، Underflow و FloatOperation.
برای هر سیگنال، یک پرچم و یک فعالساز تله وجود دارد. هنگامی که یک سیگنال رخ میدهد، پرچم آن روی ۱ تنظیم میشود؛ سپس اگر فعالساز تله روی ۱ تنظیم شده باشد، یک استثنا پرتاب میشود. پرچمها پایا هستند، بنابراین کاربر باید پیش از پایش یک محاسبه، آنها را بازنشانی کند.
همچنین ملاحظه نمائید
مشخصات حساب اعشاری عمومی IBM، The General Decimal Arithmetic Specification.
آموزش شروع سریع¶
آغاز معمول استفاده از اعداد اعشاری، ایمپورت کردن ماژول، مشاهدهی زمینهی فعلی با getcontext() و، در صورت لزوم، تنظیم مقادیر جدید برای دقت، گرد کردن، یا تلههای فعال است:
>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
InvalidOperation])
>>> getcontext().prec = 7 # Set a new precision
نمونههای Decimal را میتوان از اعداد صحیح، رشتهها، اعداد اعشاری یا تاپلها ساخت. ساخت از یک عدد صحیح یا عدد اعشاری، تبدیل دقیق مقدار آن عدد صحیح یا عدد اعشاری را انجام میدهد. اعداد Decimal شامل مقادیر ویژهای مانند NaN هستند که مخفف «Not a number» است، همچنین Infinity مثبت و منفی، و -0:
>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.4142135623730951')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')
اگر سیگنال FloatOperation به دام بیفتد، ترکیب ناخواستهی decimalها و floatها در سازندهها یا مقایسههای ترتیبی باعث پرتاب یک استثنا میشود:
>>> c = getcontext()
>>> c.traps[FloatOperation] = True
>>> Decimal(3.14)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') < 3.7
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') == 3.5
True
اضافه شده در نسخهی 3.3.
معناداری یک Decimal جدید صرفاً با تعداد ارقام ورودی تعیین میشود. دقت و گرد کردن زمینه فقط در حین عملیات حسابی اعمال میشوند.
>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')
در صورت تجاوز از محدودیتهای داخلی نسخه C، ساخت یک decimal باعث پرتاب InvalidOperation میشود:
>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
تغییر یافته در نسخهی 3.3.
دسیمالها با بسیاری از بخشهای دیگر پایتون بهخوبی تعامل میکنند. در اینجا یک سیرک پرنده کوچک ممیز شناور دسیمال آمده است:
>>> data = list(map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()))
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1)
Decimal('1.3')
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')
دسیمالها را میتوان (با تابع توکار format() یا افاسترینگها) بهصورت نماد ممیز ثابت یا علمی قالببندی کرد، با استفاده از همان سینتکس قالببندی (مراجعه کنید به زبان کوچک مشخصات قالببندی) که نوع توکار float دارد:
>>> format(Decimal('2.675'), "f")
'2.675'
>>> format(Decimal('2.675'), ".2f")
'2.68'
>>> f"{Decimal('2.675'):.2f}"
'2.68'
>>> format(Decimal('2.675'), ".2e")
'2.68e+0'
>>> with localcontext() as ctx:
... ctx.rounding = ROUND_DOWN
... print(format(Decimal('2.675'), ".2f"))
...
2.67
و برخی از توابع ریاضی نیز برای Decimal در دسترس هستند:
>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')
متد quantize() یک عدد را به یک توان ثابت گرد میکند. این متد برای کاربردهای مالی که اغلب نتایج را به تعداد ثابتی از ارقام اعشار گرد میکنند، مفید است:
>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')
همانطور که در بالا نشان داده شد، تابع getcontext() به زمینهی جاری دسترسی پیدا میکند و امکان تغییر تنظیمات را فراهم میکند. این رویکرد نیازهای بیشتر برنامههای کاربردی را برآورده میکند.
برای کارهای پیشرفتهتر، ممکن است ایجاد زمینههای جایگزین با استفاده از سازندهی Context() مفید باشد. برای فعال کردن یک زمینه جایگزین، از تابع setcontext() استفاده کنید.
مطابق با استاندارد، ماژول decimal دو زمینه استاندارد آماده استفاده، BasicContext و ExtendedContext را فراهم میکند. مورد اول بهویژه برای اشکالزدایی مفید است، زیرا بسیاری از تلهها فعال هستند:
>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')
>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#143>", line 1, in -toplevel-
Decimal(42) / Decimal(0)
DivisionByZero: x / 0
زمینهها همچنین پرچمهای سیگنال برای پایش شرایط استثنایی پیشآمده در حین محاسبات دارند. این پرچمها تا زمانی که بهصراحت پاک نشوند، فعال باقی میمانند؛ بنابراین بهتر است پیش از هر مجموعهای از محاسبات تحت پایش، پرچمها را با استفاده از متد clear_flags() پاک کنید.
>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
مدخل flags نشان میدهد که تقریب گویای عدد پی گرد شده است (ارقام فراتر از دقت زمینه دور ریخته شدند) و نتیجه نادقیق است (برخی از ارقام دور ریختهشده غیرصفر بودند).
تلههای منفرد با استفاده از دیکشنری موجود در ویژگی traps یک زمینه تنظیم میشوند:
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#112>", line 1, in -toplevel-
Decimal(1) / Decimal(0)
DivisionByZero: x / 0
بیشتر برنامهها زمینهی جاری را تنها یک بار، در آغاز برنامه تنظیم میکنند. و در بسیاری از برنامههای کاربردی، دادهها درون یک حلقه با یک تبدیل (cast) واحد به Decimal تبدیل میشوند. پس از تنظیم زمینه و ایجاد مقادیر Decimal، بخش عمدهی برنامه دادهها را دقیقاً مانند سایر انواع عددی پایتون دستکاری میکند.
اشیای Decimal¶
- class decimal.Decimal(value='0', context=None)¶
یک شیء جدید
Decimalبر اساس value بسازید.value میتواند یک عدد صحیح، رشته، تاپل،
float، یا یک شیءDecimalدیگر باشد. اگر value ارائه نشود،Decimal('0')برگردانده میشود. اگر value یک رشته باشد، باید پس از حذف نویسههای فضای سفید در ابتدا و انتها، و همچنین زیرسطرها در سراسر آن، با سینتکس رشته عددی اعشاری مطابقت کند:sign ::= '+' | '-' digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' indicator ::= 'e' | 'E' digits ::= digit [digit]... decimal-part ::= digits '.' [digits] | ['.'] digits exponent-part ::= indicator [sign] digits infinity ::= 'Infinity' | 'Inf' nan ::= 'NaN' [digits] | 'sNaN' [digits] numeric-value ::= decimal-part [exponent-part] | infinity numeric-string ::= [sign] numeric-value | [sign] nan
سایر ارقام دهدهی یونیکد نیز در هر جایی که
digitدر بالا آمده است، مجاز هستند. این موارد شامل ارقام دهدهی از الفباهای مختلف دیگر (برای مثال، ارقام عربی-هندی و دوناگری) بههمراه ارقام تمامعرض'\uff10'تا'\uff19'میشوند. بزرگی و کوچکی حروف اهمیت ندارد، بنابراین، برای مثال،inf،Inf،INFINITYوiNfINityهمگی نگارشهای قابلقبول برای بینهایت مثبت هستند.اگر value یک
tupleباشد، باید سه کامپوننت داشته باشد: یک علامت (0برای مثبت یا1برای منفی)، یکtupleاز ارقام، و یک توان عدد صحیح. برای مثال،Decimal((0, (1, 4, 1, 4), -3))Decimal('1.414')را برمیگرداند.اگر value یک
floatباشد، مقدار ممیز شناور دودویی بدون از دست دادن دقت به معادل دهدهی دقیق خود تبدیل میشود. این تبدیل اغلب ممکن است به ۵۳ رقم دقت یا بیشتر نیاز داشته باشد. برای مثال،Decimal(float('1.1'))بهDecimal('1.100000000000000088817841970012523233890533447265625')تبدیل میشود.دقت زمینه بر تعداد ارقام ذخیرهشده تأثیر نمیگذارد. این موضوع منحصراً بر اساس تعداد ارقام موجود در مقدار تعیین میشود. برای مثال،
Decimal('3.00000')حتی اگر دقت زمینه فقط ۳ باشد، هر ۵ صفر را ثبت میکند.هدف از آرگومان context تعیین این است که اگر value رشتهای نامعتبر باشد، چه کاری انجام شود. اگر زمینه برای
InvalidOperationدام داشته باشد، یک استثنا پرتاب میشود؛ در غیر این صورت، سازنده یک Decimal جدید با مقدارNaNبرمیگرداند.پس از ساخته شدن، اشیای
Decimalتغییرناپذیر هستند.تغییر یافته در نسخهی 3.2: آرگومان سازنده اکنون میتواند یک نمونه
floatباشد.تغییر یافته در نسخهی 3.3: آرگومانهای
floatدر صورت تنظیم بودن تلهیFloatOperationیک استثنا پرتاب میکنند. بهطور پیشفرض، این تله غیرفعال است.تغییر یافته در نسخهی 3.6: زیرسطرها برای گروهبندی مجاز هستند، همانگونه که در مقادیر لفظی عدد صحیح و ممیز شناور در کد استفاده میشوند.
اشیای ممیز شناور اعشاری بسیاری از ویژگیها را با سایر انواع عددی توکار مانند
floatوintبه اشتراک میگذارند. تمام عملیات ریاضی معمول و متدهای ویژه قابل اعمال هستند. به همین ترتیب، اشیای اعشاری را میتوان کپی کرد، پیکل کرد، چاپ کرد، بهعنوان کلیدهای دیکشنری استفاده کرد، بهعنوان عناصر مجموعه استفاده کرد، مقایسه کرد، مرتب کرد و به نوع دیگری (مانندfloatیاint) تبدیل کرد.تفاوتهای کوچکی میان عملیات حسابی بر روی اشیای Decimal و عملیات حسابی بر روی اعداد صحیح و اعداد اعشاری وجود دارد. هنگامی که عملگر باقیمانده
%بر روی اشیای Decimal اعمال شود، علامت نتیجه، علامت مقسوم است، نه علامت مقسومعلیه:>>> (-7) % 4 1 >>> Decimal(-7) % Decimal(4) Decimal('-3')
عملگر تقسیم عدد صحیح
//بهطور مشابه رفتار میکند و به جای کف خارجقسمت واقعی، بخش عدد صحیح آن را (با قطع به سمت صفر) برمیگرداند تا اتحاد معمولx == (x // y) * y + x % yحفظ شود:>>> -7 // 4 -2 >>> Decimal(-7) // Decimal(4) Decimal('-1')
عملگرهای
%و//بهترتیب عملیاتremainderوdivide-integerرا همانگونه که در مشخصات آمده است پیادهسازی میکنند.بهطور کلی نمیتوان اشیاء Decimal را در عملیات حسابی با floatها یا نمونههایی از
fractions.Fractionترکیب کرد: برای مثال، تلاش برای جمع کردن یکDecimalبا یکfloatباعث پرتاب یکTypeErrorمیشود. با این حال، میتوان از عملگرهای مقایسهای پایتون برای مقایسهی یک نمونهیDecimalیعنیxبا عدد دیگریyاستفاده کرد. این کار از بروز نتایج گیجکننده هنگام انجام مقایسههای برابری میان اعدادی از انواع مختلف جلوگیری میکند.تغییر یافته در نسخهی 3.2: مقایسههای بین انواع مختلف میان نمونههای
Decimalو سایر انواع عددی اکنون بهطور کامل پشتیبانی میشوند.علاوه بر ویژگیهای عددی استاندارد، اشیای ممیز شناور اعشاری تعدادی متد تخصصی نیز دارند:
- adjusted()¶
توان تنظیمشده را پس از حذف رقمهای سمت راست ضریب تا جایی که تنها رقم نخست باقی بماند، برمیگرداند:
Decimal('321e+5').adjusted()عدد هفت را برمیگرداند. برای تعیین موقعیت باارزشترین رقم نسبت به نقطه اعشار استفاده میشود.
- as_integer_ratio()¶
یک جفت عدد صحیح
(n, d)برمیگرداند که نمونهیDecimalدادهشده را بهصورت کسر، در سادهترین حالت و با مخرج مثبت نمایش میدهد:>>> Decimal('-3.14').as_integer_ratio() (-157, 50)
این تبدیل دقیق است. برای بینهایتها، OverflowError و برای NaNها، ValueError پرتاب میشود.
اضافه شده در نسخهی 3.6.
- as_tuple()¶
نمایشی بهصورت named tuple از عدد برمیگرداند:
DecimalTuple(sign, digits, exponent).
- canonical()¶
کدگذاری کانونیکال آرگومان را برمیگرداند. در حال حاضر، کدگذاری یک نمونهی
Decimalهمیشه کانونیکال است، بنابراین این عملیات آرگومان خود را بدون تغییر برمیگرداند.
- compare(other, context=None)¶
مقادیر دو نمونه از Decimal را مقایسه میکند.
compare()یک نمونه از Decimal برمیگرداند، و اگر هر یک از دو عملوند NaN باشد، نتیجه NaN است:a یا b یک NaN باشد ==> Decimal('NaN') a < b ==> Decimal('-1') a == b ==> Decimal('0') a > b ==> Decimal('1')
- compare_signal(other, context=None)¶
این عملیات دقیقاً مشابه متد
compare()است، با این تفاوت که همه NaNها سیگنالدهی میکنند. یعنی، اگر هیچکدام از عملوندها یک NaN سیگنالدهنده (signaling NaN) نباشد، هر عملوند NaN ساکت (quiet NaN) بهعنوان یک NaN سیگنالدهنده در نظر گرفته میشود.
- compare_total(other, context=None)¶
دو عملوند را با استفاده از بازنمایی انتزاعی آنها به جای مقدار عددیشان مقایسه میکند. مشابه متد
compare()، اما نتیجه ترتیب کاملی بر نمونههایDecimalارائه میدهد. دو نمونهیDecimalبا مقدار عددی یکسان اما بازنماییهای متفاوت، در این ترتیب نابرابر مقایسه میشوند:>>> Decimal('12.0').compare_total(Decimal('12')) Decimal('-1')
NaNهای آرام و سیگنالده (signaling) نیز در ترتیب کامل گنجانده شدهاند. نتیجه این تابع
Decimal('0')است اگر هر دو عملوند نمایش یکسانی داشته باشند،Decimal('-1')است اگر عملوند اول در ترتیب کامل پایینتر از عملوند دوم باشد، وDecimal('1')است اگر عملوند اول در ترتیب کامل بالاتر از عملوند دوم باشد. برای جزئیات ترتیب کامل، به مشخصات مراجعه کنید.این عملیات تحت تأثیر زمینه قرار نمیگیرد و ساکت است: هیچ پرچمی تغییر نمیکند و هیچ گردکردنی انجام نمیشود. بهعنوان یک استثنا، نسخهی C ممکن است در صورتی که عملوند دوم نتواند بهطور دقیق تبدیل شود، استثنای InvalidOperation را پرتاب کند.
- compare_total_mag(other, context=None)¶
دو عملوند را همانند
compare_total()با استفاده از نمایش انتزاعی آنها مقایسه میکند، نه با استفاده از مقدارشان، اما علامت هر عملوند را نادیده میگیرد.x.compare_total_mag(y)معادلx.copy_abs().compare_total(y.copy_abs())است.این عملیات تحت تأثیر زمینه قرار نمیگیرد و ساکت است: هیچ پرچمی تغییر نمیکند و هیچ گردکردنی انجام نمیشود. بهعنوان یک استثنا، نسخهی C ممکن است در صورتی که عملوند دوم نتواند بهطور دقیق تبدیل شود، استثنای InvalidOperation را پرتاب کند.
- conjugate()¶
فقط self را برمیگرداند؛ این متد تنها برای انطباق با Decimal Specification است.
- copy_abs()¶
مقدار مطلق آرگومان را برمیگرداند. این عملیات از زمینه تأثیر نمیپذیرد و خاموش است: هیچ پرچمی تغییر نمیکند و هیچ گردکردنی انجام نمیشود.
- copy_negate()¶
منفی آرگومان را بازمیگرداند. این عملیات تحت تأثیر زمینه نیست و خاموش است: هیچ پرچمی تغییر نمیکند و هیچ گردکردنی انجام نمیشود.
- copy_sign(other, context=None)¶
یک کپی از عملوند اول را با علامتی که همان علامت عملوند دوم است برمیگرداند. برای مثال:
>>> Decimal('2.3').copy_sign(Decimal('-1.5')) Decimal('-2.3')
این عملیات تحت تأثیر زمینه قرار نمیگیرد و ساکت است: هیچ پرچمی تغییر نمیکند و هیچ گردکردنی انجام نمیشود. بهعنوان یک استثنا، نسخهی C ممکن است در صورتی که عملوند دوم نتواند بهطور دقیق تبدیل شود، استثنای InvalidOperation را پرتاب کند.
- exp(context=None)¶
مقدار تابع نمایی (طبیعی)
e**xرا برای عدد دادهشده برمیگرداند. نتیجه با استفاده از حالت گرد کردنROUND_HALF_EVENبهدرستی گرد میشود.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')
- classmethod from_float(f, /)¶
سازنده جایگزینی که فقط نمونههایی از
floatیاintرا میپذیرد.توجه داشته باشید که
Decimal.from_float(0.1)باDecimal('0.1')یکسان نیست. از آنجا که ۰٫۱ در نقطهشناور دودویی دقیقاً قابل بازنمایی نیست، مقدار به نزدیکترین مقدار قابل بازنمایی ذخیره میشود که0x1.999999999999ap-4است. مقدار معادل آن در مبنای ده0.1000000000000000055511151231257827021181583404541015625است.>>> Decimal.from_float(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625') >>> Decimal.from_float(float('nan')) Decimal('NaN') >>> Decimal.from_float(float('inf')) Decimal('Infinity') >>> Decimal.from_float(float('-inf')) Decimal('-Infinity')
اضافه شده در نسخهی 3.1.
- classmethod from_number(number, /)¶
سازنده جایگزینی که فقط نمونههای
float،intیاDecimalرا میپذیرد، اما رشتهها یا تاپلها را نمیپذیرد.>>> Decimal.from_number(314) Decimal('314') >>> Decimal.from_number(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625') >>> Decimal.from_number(Decimal('3.14')) Decimal('3.14')
اضافه شده در نسخهی 3.14.
- fma(other, third, context=None)¶
ضرب-جمع ادغامشده (Fused multiply-add). حاصل self*other+third را بدون گرد کردن حاصلضرب میانی self*other برمیگرداند.
>>> Decimal(2).fma(3, 5) Decimal('11')
- is_canonical()¶
اگر آرگومان کانونیکال باشد،
Trueو در غیر این صورتFalseرا برمیگرداند. در حال حاضر، یک نمونه ازDecimalهمیشه کانونیکال است، بنابراین این عملیات همیشهTrueرا برمیگرداند.
- is_finite()¶
اگر آرگومان یک عدد متناهی باشد،
Trueرا برمیگرداند، و اگر آرگومان یک بینهایت یا NaN باشد،Falseرا برمیگرداند.
- is_nan()¶
اگر آرگومان یک NaN (بیصدا یا سیگنالدهنده) باشد،
Trueو در غیر این صورتFalseرا برمیگرداند.
- is_normal(context=None)¶
اگر آرگومان یک عدد متناهی نرمال باشد،
Trueرا برمیگرداند. اگر آرگومان صفر، زیرنرمال (subnormal)، بینهایت یا یک NaN باشد،Falseرا برمیگرداند.
- is_signed()¶
اگر آرگومان علامت منفی داشته باشد،
Trueو در غیر این صورتFalseبازمیگرداند. توجه داشته باشید که صفرها و NaNها هر دو میتوانند علامت داشته باشند.
- is_zero()¶
اگر آرگومان صفر (مثبت یا منفی) باشد،
Trueرا برمیگرداند و در غیر این صورتFalseرا برمیگرداند.
- ln(context=None)¶
لگاریتم طبیعی (مبنای e) عملوند را برمیگرداند. نتیجه با استفاده از حالت گردکردن
ROUND_HALF_EVENبهدرستی گرد میشود.
- log10(context=None)¶
لگاریتم عملوند در مبنای ۱۰ را برمیگرداند. نتیجه با استفاده از حالت گرد کردن
ROUND_HALF_EVENبهدرستی گرد میشود.
- logb(context=None)¶
برای یک عدد غیرصفر، توان تعدیلشدهی عملوندش را بهعنوان یک نمونهی
Decimalبرمیگرداند. اگر عملوند صفر باشد،Decimal('-Infinity')برگردانده میشود و پرچمDivisionByZeroپرتاب میشود. اگر عملوند بینهایت باشد،Decimal('Infinity')برگردانده میشود.
- logical_and(other, context=None)¶
logical_and()یک عمل منطقی است که دو عملوند منطقی میگیرد (به عملوندهای منطقی مراجعه کنید). نتیجه،andرقمبهرقم دو عملوند است.
- logical_invert(context=None)¶
logical_invert()یک عملیات منطقی است. نتیجه، وارونگی رقمبهرقم عملوند است.
- logical_or(other, context=None)¶
logical_or()یک عملیات منطقی است که دو عملوند منطقی میگیرد (ببینید عملوندهای منطقی). نتیجه،orرقمبهرقم دو عملوند است.
- logical_xor(other, context=None)¶
logical_xor()یک عملیات منطقی است که دو عملوند منطقی را میگیرد (ببینید عملوندهای منطقی). نتیجه، یا انحصاری رقمبهرقم دو عملوند است.
- max(other, context=None)¶
مانند
max(self, other)است، با این تفاوت که پیش از برگرداندن، قاعدهی گرد کردن زمینه اعمال میشود و مقادیرNaNیا سیگنالدهی میشوند یا نادیده گرفته میشوند (بسته به زمینه و اینکه سیگنالدهنده باشند یا آرام ).
- max_mag(other, context=None)¶
مشابه متد
max()، اما مقایسه با استفاده از مقادیر مطلق عملوندها انجام میشود.
- min(other, context=None)¶
مانند
min(self, other)است، به جز اینکه قاعدهی گرد کردن زمینه پیش از بازگرداندن اعمال میشود و مقادیرNaNیا سیگنال داده میشوند یا نادیده گرفته میشوند (بسته به زمینه و اینکه آنها سیگنالدهنده باشند یا ساکت).
- min_mag(other, context=None)¶
مشابه متد
min()، اما مقایسه با استفاده از مقادیر مطلق عملوندها انجام میشود.
- next_minus(context=None)¶
بزرگترین عدد قابل نمایش در زمینهی دادهشده (یا در زمینهی نخ جاری اگر زمینهای داده نشده باشد) که از عملوند دادهشده کوچکتر است را برمیگرداند.
- next_plus(context=None)¶
کوچکترین عدد قابل بازنمایی در زمینهی دادهشده (یا در زمینهی نخ جاری اگر زمینهای داده نشده باشد) که از عملوند دادهشده بزرگتر باشد را برمیگرداند.
- next_toward(other, context=None)¶
اگر دو عملوند نابرابر باشند، نزدیکترین عدد به عملوند اول در جهت عملوند دوم را برمیگرداند. اگر هر دو عملوند از نظر عددی برابر باشند، یک کپی از عملوند اول را با علامتی برابر با علامت عملوند دوم برمیگرداند.
- normalize(context=None)¶
برای تولید مقادیر کانونیکال یک کلاس همارزی، چه در زمینه جاری و چه در زمینه مشخصشده، استفاده میشود.
این همان معنای عملیات جمع یکعملوندی را دارد، بهجز اینکه اگر نتیجه نهایی متناهی باشد، به سادهترین شکل خود تقلیل مییابد، بهطوریکه تمام صفرهای پایانی حذف میشوند و علامت آن حفظ میشود. یعنی تا زمانی که ضریب غیرصفر و مضربی از ده باشد، ضریب بر ده تقسیم میشود و توان ۱ واحد افزایش مییابد. در غیر این صورت (ضریب صفر است)، توان برابر ۰ قرار میگیرد. در همه حالتها علامت بدون تغییر میماند.
برای مثال،
Decimal('32.100')وDecimal('0.321000e+2')هر دو به مقدار معادلDecimal('32.1')نرمال میشوند.توجه داشته باشید که گرد کردن پیش از سادهسازی به سادهترین شکل اعمال میشود.
در آخرین نسخههای مشخصات، این عملیات همچنین با نام
reduceنیز شناخته میشود.
- number_class(context=None)¶
رشتهای را برمیگرداند که کلاس عملوند را توصیف میکند. مقدار برگرداندهشده یکی از ده رشته زیر است.
"-Infinity"، که نشان میدهد عملوند بینهایت منفی است."-Normal"، نشان میدهد که عملوند یک عدد نرمال منفی است."-Subnormal"، که نشان میدهد عملوند منفی و زیرنرمال است."-Zero"، که نشان میدهد عملوند یک صفر منفی است."+Zero"، نشان میدهد که عملوند یک صفر مثبت است."+Subnormal"، نشان میدهد که عملوند مثبت و زیرنرمال است."+Normal"، که نشان میدهد عملوند یک عدد نرمال مثبت است."+Infinity"، که نشاندهندهی بینهایت مثبت بودن عملوند است."NaN"، که نشان میدهد عملوند یک NaN ساکت (Not a Number) است."sNaN"، که نشان میدهد عملوند یک NaN سیگنالدهنده است.
- quantize(exp, rounding=None, context=None)¶
مقداری برابر با عملوند اول برمیگرداند که پس از گرد کردن، توان عملوند دوم را دارد.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')
برخلاف سایر عملیات، اگر طول ضریب پس از عملیات کوانتایز (quantize) بیشتر از دقت باشد، یک
InvalidOperationعلامتدهی میشود. این تضمین میکند که، مگر اینکه شرایط خطایی وجود داشته باشد، توان کوانتایزشده همواره برابر با توان عملوند سمت راست است.همچنین برخلاف سایر عملیاتها، quantize هرگز سیگنال Underflow را صادر نمیکند، حتی اگر نتیجه زیرنرمال و غیردقیق باشد.
اگر توان عملوند دوم بزرگتر از توان عملوند اول باشد، ممکن است گرد کردن لازم باشد. در این حالت، حالت گرد کردن توسط آرگومان
roundingدر صورتی که داده شده باشد تعیین میشود، در غیر این صورت توسط آرگومانcontextدادهشده تعیین میشود؛ اگر هیچکدام از آرگومانها داده نشوند، از حالت گرد کردن زمینهی نخ جاری استفاده میشود.هر زمان که توان حاصل بزرگتر از
Emaxیا کوچکتر ازEtiny()باشد، یک خطا بازگردانده میشود.
- radix()¶
Decimal(10)را برمیگرداند، یعنی مبنایی (پایهای) که کلاسDecimalتمام محاسبات خود را در آن انجام میدهد. برای سازگاری با مشخصات گنجانده شده است.
- remainder_near(other, context=None)¶
باقیماندهی تقسیم self بر other را برمیگرداند. این با
self % otherدر این تفاوت دارد که علامت باقیمانده بهگونهای انتخاب میشود که مقدار مطلق آن کمینه شود. دقیقتر، مقدار بازگشتیself - n * otherاست که در آنnنزدیکترین عدد صحیح به مقدار دقیقself / otherاست، و اگر دو عدد صحیح به یک اندازه نزدیک باشند، عدد زوج انتخاب میشود.اگر نتیجه صفر باشد، علامت آن همان علامت self خواهد بود.
>>> Decimal(18).remainder_near(Decimal(10)) Decimal('-2') >>> Decimal(25).remainder_near(Decimal(10)) Decimal('5') >>> Decimal(35).remainder_near(Decimal(10)) Decimal('-5')
- rotate(other, context=None)¶
نتیجهی چرخاندن ارقام اولین عملوند به میزان مشخصشده توسط دومین عملوند را برمیگرداند. دومین عملوند باید عدد صحیحی در بازهی منفی دقت تا دقت باشد. مقدار مطلق دومین عملوند، تعداد موقعیتهای چرخش را مشخص میکند. اگر دومین عملوند مثبت باشد، چرخش به سمت چپ است؛ در غیر این صورت، چرخش به سمت راست است. در صورت لزوم، سمت چپ ضریب اولین عملوند با صفرها پر میشود تا طول آن برابر با دقت شود. علامت و توان اولین عملوند بدون تغییر میمانند.
- same_quantum(other, context=None)¶
بررسی میکند که آیا self و other توان یکسانی دارند یا اینکه هر دو
NaNهستند.این عملیات تحت تأثیر زمینه قرار نمیگیرد و ساکت است: هیچ پرچمی تغییر نمیکند و هیچ گردکردنی انجام نمیشود. بهعنوان یک استثنا، نسخهی C ممکن است در صورتی که عملوند دوم نتواند بهطور دقیق تبدیل شود، استثنای InvalidOperation را پرتاب کند.
- scaleb(other, context=None)¶
عملوند اول را با توان تنظیمشده توسط عملوند دوم بازمیگرداند. معادل آن، عملوند اول ضربشده در
10**otherرا بازمیگرداند. عملوند دوم باید یک عدد صحیح باشد.
- shift(other, context=None)¶
نتیجهی جابهجایی ارقام عملوند اول به مقدار مشخصشده توسط عملوند دوم را برمیگرداند. عملوند دوم باید عدد صحیحی در بازهی منفی دقت تا دقت باشد. قدر مطلق عملوند دوم، تعداد جایگاههای جابهجایی را مشخص میکند. اگر عملوند دوم مثبت باشد، جابهجایی به سمت چپ است؛ در غیر این صورت، جابهجایی به سمت راست است. ارقامی که به داخل ضریب جابهجا میشوند، صفر هستند. علامت و توان عملوند اول تغییر نمیکنند.
- sqrt(context=None)¶
ریشه دوم آرگومان را با دقت کامل بازمیگرداند.
- to_eng_string(context=None)¶
به یک رشته تبدیل میکند، و در صورت نیاز به توان، از نماد مهندسی استفاده میکند.
در نمادگذاری مهندسی، توان مضربی از ۳ است. این موضوع میتواند تا ۳ رقم را در سمت چپ نقطه اعشار باقی بگذارد و ممکن است به افزودن یک یا دو صفر انتهایی نیاز داشته باشد.
برای مثال، این
Decimal('123E+1')را بهDecimal('1.23E+3')تبدیل میکند.
- to_integral(rounding=None, context=None)¶
یکسان با متد
to_integral_value(). نامto_integralبرای سازگاری با نسخههای قدیمیتر حفظ شده است.
- to_integral_exact(rounding=None, context=None)¶
به نزدیکترین عدد صحیح گرد میشود، و در صورت وقوع گرد کردن، بنا به مورد
InexactیاRoundedسیگنال داده میشود. حالت گرد کردن در صورت داده شدن پارامترroundingبا آن، و در غیر این صورت باcontextدادهشده تعیین میشود. اگر هیچکدام از پارامترها داده نشود، حالت گرد کردن زمینهی جاری استفاده میشود.
- to_integral_value(rounding=None, context=None)¶
به نزدیکترین عدد صحیح گرد میکند، بدون اینکه
InexactیاRoundedسیگنال داده شود. در صورت داده شدن، rounding را اعمال میکند؛ در غیر این صورت، از روش گرد کردن در context ارائهشده یا زمینهی جاری استفاده میکند.
میتوان اعداد اعشاری را با استفاده از تابع
round()گرد کرد:- round(number)
- round(number, ndigits)
اگر ndigits داده نشود یا
Noneباشد، نزدیکترینintبه number بازگردانده میشود، بهگونهای که موارد تساوی در گرد کردن به عدد زوج گرد میشوند و حالت گرد کردن زمینهیDecimalنادیده گرفته میشود. اگر number یک بینهایت باشد،OverflowErrorپرتاب میشود و اگر یک NaN (ساکت یا سیگنالدهی) باشد،ValueErrorپرتاب میشود.اگر ndigits یک
intباشد، حالت گرد کردن زمینه رعایت میشود و یکDecimalبرگردانده میشود که نشاندهندهی number گردشده به نزدیکترین مضربDecimal('1E-ndigits')است؛ در این حالت،round(number, ndigits)معادلself.quantize(Decimal('1E-ndigits'))است. اگر number یک NaN ساکت (quiet NaN) باشد،Decimal('NaN')را برمیگرداند. اگر number یک بینهایت یا یک NaN سیگنالدهنده باشد، یا اگر طول ضریب پس از عملیات quantize بیشتر از دقت زمینهی فعلی باشد،InvalidOperationرا پرتاب میکند. به عبارت دیگر، برای حالتهای غیرمرزی:اگر ndigits مثبت باشد، number را که تا ndigits رقم اعشاری گرد شده است برمیگرداند؛
اگر ndigits صفر باشد، number را که به نزدیکترین عدد صحیح گرد شده است برمیگرداند؛
اگر ndigits منفی باشد، number را که به نزدیکترین مضرب
10**abs(ndigits)گرد شده است، برمیگرداند.
برای مثال:
>>> from decimal import Decimal, getcontext, ROUND_DOWN >>> getcontext().rounding = ROUND_DOWN >>> round(Decimal('3.75')) # context rounding ignored 4 >>> round(Decimal('3.5')) # round-ties-to-even 4 >>> round(Decimal('3.75'), 0) # uses the context rounding Decimal('3') >>> round(Decimal('3.75'), 1) Decimal('3.7') >>> round(Decimal('3.75'), -1) Decimal('0E+1')
عملوندهای منطقی¶
متدهای logical_and()، logical_invert()، logical_or() و logical_xor() انتظار دارند که آرگومانهای آنها عملوندهای منطقی باشند. یک عملوند منطقی نمونهای از Decimal است که توان و علامت آن هر دو صفر هستند و تمام ارقام آن یا 0 هستند یا 1.
اشیاء زمینه¶
زمینهها محیطهایی برای عملیات حسابی هستند. آنها دقت را کنترل میکنند، قواعد گرد کردن را تنظیم میکنند، تعیین میکنند که کدام سیگنالها بهعنوان استثنا در نظر گرفته شوند، و بازهی توانها را محدود میکنند.
هر نخ زمینهی جاری خود را دارد که با استفاده از توابع getcontext() و setcontext() قابل دسترسی یا تغییر است:
- decimal.getcontext()¶
زمینه فعلی برای نخ فعال را برمیگرداند.
- decimal.setcontext(c, /)¶
زمینه فعلی نخ فعال را روی c تنظیم کنید.
شما همچنین میتوانید از دستور with و تابع localcontext() برای تغییر موقت زمینهی فعال استفاده کنید.
- decimal.localcontext(ctx=None, **kwargs)¶
یک مدیر زمینه برمیگرداند که هنگام ورود به دستور with، زمینه فعلی نخ فعال را به یک کپی از ctx تنظیم میکند و هنگام خروج از دستور with، زمینه قبلی را بازگردانی میکند. اگر هیچ زمینهای مشخص نشده باشد، از یک کپی از زمینه فعلی استفاده میشود. آرگومان kwargs برای تنظیم ویژگیهای زمینه جدید استفاده میشود.
برای مثال، کد زیر دقت اعشاری کنونی را روی ۴۲ رقم اعشار تنظیم میکند، یک محاسبه انجام میدهد و سپس بهطور خودکار زمینه پیشین را بازمیگرداند:
from decimal import localcontext with localcontext() as ctx: ctx.prec = 42 # Perform a high precision calculation s = calculate_something() s = +s # Round the final result back to the default precision
با استفاده از آرگومانهای کلیدواژهای، کد بهشکل زیر خواهد بود:
from decimal import localcontext with localcontext(prec=42) as ctx: s = calculate_something() s = +s
اگر kwargs ویژگیای را ارائه دهد که
Contextاز آن پشتیبانی نمیکند،TypeErrorپرتاب میشود. اگر kwargs مقدار نامعتبری برای یک ویژگی ارائه دهد، یاTypeErrorیاValueErrorپرتاب میشود.تغییر یافته در نسخهی 3.11:
localcontext()اکنون از تنظیم ویژگیهای زمینه از طریق آرگومانهای کلیدواژهای پشتیبانی میکند.
- decimal.IEEEContext(bits)¶
یک شیء زمینه را برمیگرداند که با مقادیر مناسب برای یکی از قالبهای مبادلهای IEEE مقداردهی اولیهشده است. آرگومان باید مضربی از ۳۲ و کمتر از
IEEE_CONTEXT_MAX_BITSباشد.اضافه شده در نسخهی 3.14.
همچنین میتوان زمینههای جدید را با استفاده از سازندهی Context که در زیر توضیح داده شده است، ایجاد کرد. علاوه بر این، این ماژول سه زمینهی از پیش ساختهشده ارائه میدهد:
- decimal.BasicContext¶
این یک زمینه استاندارد است که توسط مشخصات عمومی محاسبات اعشاری (General Decimal Arithmetic Specification) تعریف شده است. دقت روی ۹ تنظیم شده است. گرد کردن روی
ROUND_HALF_UPتنظیم شده است. همه پرچمها پاک شدهاند. همه تلهها فعال شدهاند (بهعنوان استثنا در نظر گرفته میشوند)، به جزInexact،RoundedوSubnormal.چون بسیاری از تلهها فعال هستند، این زمینه برای اشکالزدایی مفید است.
- decimal.ExtendedContext¶
این یک زمینه استاندارد است که توسط مشخصات عمومی محاسبات اعشاری (General Decimal Arithmetic Specification) تعریف شده است. دقت روی ۹ تنظیم شده است. گرد کردن روی
ROUND_HALF_EVENتنظیم شده است. همه پرچمها پاک شدهاند. هیچ تلهای فعال نیست (تا استثناها در حین محاسبات پرتاب نشوند).از آنجا که تلهها غیرفعال هستند، این زمینه برای برنامههایی مفید است که ترجیح میدهند بهجای پرتاب استثنا، مقدار نتیجه
NaNیاInfinityباشد. این امر به برنامه اجازه میدهد که اجرا را در شرایطی که در غیر این صورت موجب توقف برنامه میشدند، به پایان برساند.
- decimal.DefaultContext¶
این زمینه توسط سازندهی
Contextبهعنوان یک نمونهی اولیه برای زمینههای جدید استفاده میشود. تغییر یک فیلد (مانند دقت) باعث تغییر پیشفرض برای زمینههای جدید ایجادشده توسط سازندهیContextمیشود.این زمینه بیشترین کاربرد را در محیطهای چندنخی دارد. تغییر یکی از فیلدها پیش از آغاز نخها، بهمنزلهی تنظیم پیشفرضهای سراسری سیستم است. تغییر فیلدها پس از آغاز نخها توصیه نمیشود، زیرا نیازمند همگامسازی نخها برای جلوگیری از شرایط رقابتی خواهد بود.
در محیطهای تکنخی، بهتر است اصلاً از این زمینه استفاده نکنید. در عوض، بهسادگی زمینهها را بهصراحت همانطور که در زیر توضیح داده شده است ایجاد کنید.
مقادیر پیشفرض عبارتاند از
Context.prec=28،Context.rounding=ROUND_HALF_EVEN، و تلههای فعال برایOverflow،InvalidOperationوDivisionByZero.
علاوه بر سه زمینهی فراهمشده، میتوان زمینههای جدید را با سازندهی Context ایجاد کرد.
- class decimal.Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)¶
یک زمینه جدید ایجاد میکند. اگر فیلدی مشخصنشده باشد یا
Noneباشد، مقادیر پیشفرض ازDefaultContextکپی میشوند. اگر فیلد flags مشخصنشده باشد یاNoneباشد، تمام پرچمها پاک میشوند.- rounding¶
یکی از ثابتهای فهرستشده در بخش Rounding Modes.
- traps¶
- flags¶
فهرستهایی از هر سیگنالی که باید تنظیم شود. بهطور کلی، زمینههای جدید فقط باید تلهها را تنظیم کنند و پرچمها را پاک باقی بگذارند.
- Emin¶
- Emax¶
اعداد صحیحی که کرانهای بیرونی مجاز برای توانها را مشخص میکنند. Emin باید در بازهی [
MIN_EMIN،0] باشد، Emax در بازهی [0،MAX_EMAX].
- capitals¶
یا
0یا1(پیشفرض). اگر روی1تنظیم شود، توانها باEبزرگ چاپ میشوند؛ در غیر این صورت، ازeکوچک استفاده میشود:Decimal('6.02e+23').
- clamp¶
یا
0(پیشفرض) یا1. اگر روی1تنظیم شود، توانeنمونهیDecimalقابلنمایش در این زمینه، بهطور دقیق به محدودهEmin - prec + 1 <= e <= Emax - prec + 1محدود میشود. اگر clamp برابر0باشد، شرط ضعیفتری برقرار است: توان تنظیمشدهی نمونهیDecimalحداکثرEmaxاست. هنگامی که clamp برابر1باشد، توان یک عدد عادی بزرگ، در صورت امکان، کاهش مییابد و تعداد متناظری صفر به ضریب آن اضافه میشود تا محدودیتهای توان رعایت شود؛ این کار مقدار عدد را حفظ میکند، اما اطلاعات مربوط به صفرهای انتهایی معنادار را از دست میدهد. برای مثال:>>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999') Decimal('1.23000E+999')
مقدار clamp (محدودسازی) برابر با
1امکان سازگاری با قالبهای مبادلهای اعشاری با عرض ثابت مشخصشده در IEEE 754 را فراهم میکند.
کلاس
Contextچندین متد با کاربرد عمومی و همچنین تعداد زیادی متد برای انجام عملیات حسابی بهصورت مستقیم در یک زمینهی دادهشده تعریف میکند. علاوه بر این، به ازای هر یک از متدهایDecimalکه در بالا توضیح داده شدهاند (بهاستثنای متدهایadjusted()وas_tuple())، یک متد متناظر درContextوجود دارد. برای مثال، برای یک نمونهیContextبه نامCو یک نمونهیDecimalبه نامx، عبارتC.exp(x)معادلx.exp(context=C)است. هر متدContextدر هر جا که یک نمونهی Decimal پذیرفته شود، یک عدد صحیح پایتون (نمونهای ازint) را میپذیرد.- clear_flags()¶
همهی پرچمها را به
0بازنشانی میکند.
- clear_traps()¶
همهی تلهها را به
0بازنشانی میکند.اضافه شده در نسخهی 3.3.
- copy()¶
یک کپی از زمینه را برمیگرداند.
- copy_decimal(num, /)¶
یک رونوشت از نمونهی Decimal به نام num برمیگرداند.
- create_decimal(num='0', /)¶
یک نمونه جدید از Decimal را از num ایجاد میکند، اما از self بهعنوان زمینه استفاده میکند. برخلاف سازندهی
Decimal، دقت زمینه، روش گرد کردن، پرچمها و تلهها در تبدیل اعمال میشوند.این مفید است، زیرا ثابتها اغلب با دقتی بیشتر از حد نیاز برنامه ارائه میشوند. مزیت دیگر این است که گرد کردن بلافاصله اثرات ناخواستهی ارقام فراتر از دقت فعلی را حذف میکند. در مثال زیر، استفاده از ورودیهای گردنشده به این معناست که افزودن صفر به یک مجموع میتواند نتیجه را تغییر دهد:
>>> getcontext().prec = 3 >>> Decimal('3.4445') + Decimal('1.0023') Decimal('4.45') >>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023') Decimal('4.44')
این متد عملیات تبدیل به عددِ مشخصات IBM را پیادهسازی میکند. اگر آرگومان یک رشته باشد، هیچگونه فضای سفید یا زیرخطی در ابتدا یا انتها مجاز نیست.
- create_decimal_from_float(f, /)¶
یک نمونه جدید Decimal از float f ایجاد میکند، اما گرد کردن با استفاده از self بهعنوان زمینه انجام میشود. برخلاف متد کلاس
Decimal.from_float()، دقت زمینه، روش گرد کردن، پرچمها و تلهها بر تبدیل اعمال میشوند.>>> context = Context(prec=5, rounding=ROUND_DOWN) >>> context.create_decimal_from_float(math.pi) Decimal('3.1415') >>> context = Context(prec=5, traps=[Inexact]) >>> context.create_decimal_from_float(math.pi) Traceback (most recent call last): ... decimal.Inexact: None
اضافه شده در نسخهی 3.1.
- Etiny()¶
مقداری برابر با
Emin - prec + 1برمیگرداند که کمترین مقدار توان برای نتایج زیرنرمال است. هنگامی که زیرریز (underflow) رخ میدهد، توان رویEtinyتنظیم میشود.
- Etop()¶
مقداری برابر با
Emax - prec + 1برمیگرداند.
رویکرد معمول برای کار با اعداد اعشاری، ایجاد نمونههای
Decimalو سپس اعمال عملیات حسابی است که در زمینهی جاری برای نخ فعال انجام میشوند. رویکرد جایگزین، استفاده از متدهای زمینه برای محاسبه در یک زمینهی مشخص است. این متدها مشابه متدهای کلاسDecimalهستند و در اینجا تنها بهاختصار بازگو شدهاند.- abs(x, /)¶
مقدار مطلق x را برمیگرداند.
- add(x, y, /)¶
مجموع x و y را برمیگرداند.
- canonical(x, /)¶
همان شیء Decimal یعنی x را بازمیگرداند.
- compare(x, y, /)¶
x و y را بهصورت عددی مقایسه میکند.
- compare_signal(x, y, /)¶
مقادیر دو عملوند را بهصورت عددی مقایسه میکند.
- compare_total(x, y, /)¶
دو عملوند را با استفاده از نمایش انتزاعی آنها مقایسه میکند.
- compare_total_mag(x, y, /)¶
دو عملوند را با استفاده از بازنمایی انتزاعی آنها، با چشمپوشی از علامت، مقایسه میکند.
- copy_abs(x, /)¶
نسخهای از x برمیگرداند که علامت آن روی ۰ تنظیم شده است.
- copy_negate(x, /)¶
یک کپی از x با علامت معکوسشده برمیگرداند.
- copy_sign(x, y, /)¶
علامت را از y به x کپی میکند.
- divide(x, y, /)¶
x تقسیمشده بر y را برمیگرداند.
- divide_int(x, y, /)¶
حاصل تقسیم x بر y را بهصورت یک عدد صحیح بریدهشده برمیگرداند.
- divmod(x, y, /)¶
دو عدد را تقسیم میکند و بخش صحیح نتیجه را برمیگرداند.
- exp(x, /)¶
e ** xرا برمیگرداند.
- fma(x, y, z, /)¶
حاصلضرب x در y بهعلاوه z را برمیگرداند.
- is_canonical(x, /)¶
اگر x کانونیکال باشد،
Trueرا برمیگرداند؛ در غیر این صورتFalseرا برمیگرداند.
- is_finite(x, /)¶
اگر x متناهی باشد،
Trueرا برمیگرداند؛ در غیر این صورتFalseرا برمیگرداند.
- is_infinite(x, /)¶
اگر x بینهایت باشد،
Trueرا برمیگرداند؛ در غیر این صورتFalseرا برمیگرداند.
- is_nan(x, /)¶
اگر x یک qNaN یا sNaN باشد،
Trueبرمیگرداند؛ در غیر این صورتFalseبرمیگرداند.
- is_normal(x, /)¶
اگر x یک عدد عادی باشد،
Trueرا برمیگرداند؛ در غیر این صورتFalseرا برمیگرداند.
- is_qnan(x, /)¶
اگر x یک NaN ساکت (quiet NaN) باشد،
Trueرا برمیگرداند؛ در غیر این صورتFalseرا برمیگرداند.
- is_signed(x, /)¶
اگر x منفی باشد،
Trueرا برمیگرداند؛ در غیر این صورتFalseرا برمیگرداند.
- is_snan(x, /)¶
اگر x یک NaN سیگنالدهنده باشد،
Trueرا برمیگرداند؛ در غیر این صورتFalseرا برمیگرداند.
- is_subnormal(x, /)¶
اگر x زیرنرمال باشد،
Trueرا برمیگرداند؛ در غیر این صورتFalseرا برمیگرداند.
- is_zero(x, /)¶
اگر x صفر باشد،
Trueرا برمیگرداند؛ در غیر این صورتFalseرا برمیگرداند.
- ln(x, /)¶
لگاریتم طبیعی x (مبنای e) را برمیگرداند.
- log10(x, /)¶
لگاریتم x در مبنای ۱۰ را برمیگرداند.
- logb(x, /)¶
توان مرتبهی بزرگی پرارزشترین رقم (MSD) عملوند را برمیگرداند.
- logical_and(x, y, /)¶
عملیات منطقی and را بین رقمهای هر عملوند اعمال میکند.
- logical_invert(x, /)¶
تمام ارقام x را معکوس کنید.
- logical_or(x, y, /)¶
عملیات منطقی or را بین ارقام هر عملوند اعمال میکند.
- logical_xor(x, y, /)¶
عملیات منطقی xor را بین رقمهای هر عملوند اعمال میکند.
- max(x, y, /)¶
دو مقدار را بهصورت عددی مقایسه میکند و بیشینه را برمیگرداند.
- max_mag(x, y, /)¶
مقادیر را بهصورت عددی با نادیده گرفتن علامت آنها مقایسه میکند.
- min(x, y, /)¶
دو مقدار را بهصورت عددی مقایسه میکند و کمینه را برمیگرداند.
- min_mag(x, y, /)¶
مقادیر را بهصورت عددی با نادیده گرفتن علامت آنها مقایسه میکند.
- minus(x, /)¶
منها با عملگر پیشوندی یکعملوندی منها در پایتون متناظر است.
- multiply(x, y, /)¶
حاصلضرب x و y را برمیگرداند.
- next_minus(x, /)¶
بزرگترین عدد قابل نمایش کوچکتر از x را بازمیگرداند.
- next_plus(x, /)¶
کوچکترین عدد قابلنمایش بزرگتر از x را برمیگرداند.
- next_toward(x, y, /)¶
نزدیکترین عدد به x را در جهت به سمت y برمیگرداند.
- normalize(x, /)¶
x را به سادهترین شکل خود تقلیل میدهد.
- number_class(x, /)¶
نشانگر کلاس x را برمیگرداند.
- plus(x, /)¶
Plus معادل عملگر یکعملوندی پیشوندی پلاس در پایتون است. این عملیات دقت و گرد کردن زمینه را اعمال میکند، بنابراین یک عملیات همانی نیست.
- power(x, y, modulo=None)¶
xبه توانyرا برمیگرداند و در صورت داده شدن، به پیمانهیmoduloکاهش مییابد.با دو آرگومان،
x**yمحاسبه میشود. اگرxمنفی باشد،yباید عدد صحیح باشد. نتیجه نادقیق خواهد بود، مگر اینکهyعدد صحیح باشد و نتیجه متناهی باشد و بتوان آن را دقیقاً با 'precision' رقم بیان کرد. از حالت گرد کردن زمینه استفاده میشود. نتایج در نسخهی پایتون همیشه بهدرستی گرد میشوند.Decimal(0) ** Decimal(0)منجر بهInvalidOperationمیشود، و اگرInvalidOperationبه دام نیفتد، نتیجهDecimal('NaN')خواهد بود.تغییر یافته در نسخهی 3.3: ماژول C،
power()را بر حسب توابعexp()وln()که بهدرستی گرد شدهاند محاسبه میکند. نتیجه خوشتعریف است، اما فقط «تقریباً همیشه بهدرستی گرد شده» است.با سه آرگومان،
(x**y) % moduloرا محاسبه میکند. برای قالب با سه آرگومان، محدودیتهای زیر روی آرگومانها برقرار است:هر سه آرگومان باید عدد صحیح باشند
yباید غیرمنفی باشدحداقل یکی از
xیاyباید غیرصفر باشدmoduloباید غیرصفر باشد و حداکثر 'precision' رقم داشته باشد
مقدار حاصل از
Context.power(x, y, modulo)برابر با مقداری است که از محاسبهی(x**y) % moduloبا دقت نامحدود به دست میآید، اما بهصورت کارآمدتری محاسبه میشود. توان نتیجه صفر است، صرفنظر از توانهایx،yوmodulo. نتیجه همیشه دقیق است.
- quantize(x, y, /)¶
مقداری برابر با x (گردشده) برمیگرداند که دارای توان y است.
- radix()¶
فقط ۱۰ را برمیگرداند، زیرا این Decimal است، :)
- remainder(x, y, /)¶
باقیماندهی تقسیم عدد صحیح را برمیگرداند.
علامت نتیجه، اگر غیرصفر باشد، همان علامت مقسوم اصلی است.
- remainder_near(x, y, /)¶
x - y * nرا برمیگرداند، که در آن n نزدیکترین عدد صحیح به مقدار دقیقx / yاست (اگر نتیجه ۰ باشد، علامت آن علامت x خواهد بود).
- rotate(x, y, /)¶
نسخهای چرخشیافته از x را به تعداد y بار برمیگرداند.
- same_quantum(x, y, /)¶
اگر دو عملوند توان یکسانی داشته باشند،
Trueبرمیگرداند.
- scaleb(x, y, /)¶
اولین عملوند را پس از افزودن مقدار دوم به توان آن برمیگرداند.
- shift(x, y, /)¶
رونوشتی از x برمیگرداند که y بار جابهجاشده است.
- sqrt(x, /)¶
ریشه دوم یک عدد غیرمنفی تا دقت زمینه.
- subtract(x, y, /)¶
اختلاف بین x و y را برمیگرداند.
- to_eng_string(x, /)¶
به یک رشته تبدیل میکند، و در صورت نیاز به توان، از نماد مهندسی استفاده میکند.
در نمادگذاری مهندسی، توان مضربی از ۳ است. این موضوع میتواند تا ۳ رقم را در سمت چپ نقطه اعشار باقی بگذارد و ممکن است به افزودن یک یا دو صفر انتهایی نیاز داشته باشد.
- to_integral_exact(x, /)¶
به یک عدد صحیح گرد میشود.
- to_sci_string(x, /)¶
یک عدد را با استفاده از نماد علمی به رشته تبدیل میکند.
ثابتها¶
ثابتهای این بخش تنها برای ماژول C مرتبط هستند. این ثابتها برای سازگاری در نسخه پایتون خالص نیز گنجانده شدهاند.
۳۲ بیتی |
۶۴ بیتی |
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- decimal.HAVE_THREADS¶
مقدار
Trueاست. منسوخ شده است، زیرا پایتون اکنون همیشه نخ دارد.منسوخ شده از نسخهی 3.9.
- decimal.HAVE_CONTEXTVAR¶
مقدار پیشفرض
Trueاست. اگر پایتونبا گزینهی --without-decimal-contextvar پیکربندی شده باشد، نسخهی C بهجای زمینهی محلی به همروال از زمینهی محلی به نخ استفاده میکند و مقدارFalseخواهد بود. این حالت در برخی سناریوهای زمینهی تودرتو کمی سریعتر است.اضافه شده در نسخهی 3.8.3.
حالتهای گرد کردن¶
- decimal.ROUND_CEILING¶
گرد کردن به سمت
Infinity.
- decimal.ROUND_DOWN¶
گرد کردن به سمت صفر.
- decimal.ROUND_FLOOR¶
گرد کردن به سمت
-Infinity.
- decimal.ROUND_HALF_DOWN¶
گرد کردن به نزدیکترین مقدار، در موارد مساوی به سمت صفر.
- decimal.ROUND_HALF_EVEN¶
گرد کردن به نزدیکترین مقدار، بهطوری که موارد تساوی به نزدیکترین عدد صحیح زوج گرد شوند.
- decimal.ROUND_HALF_UP¶
گرد کردن به نزدیکترین مقدار، بهطوری که در موارد تساوی، دور از صفر گرد میشود.
- decimal.ROUND_UP¶
گرد کردن به دور از صفر.
- decimal.ROUND_05UP¶
اگر آخرین رقم پس از گرد کردن به سمت صفر، ۰ یا ۵ باشد، به دور از صفر گرد میشود؛ در غیر این صورت به سمت صفر گرد میشود.
سیگنالها¶
سیگنالها نشاندهندهی شرایطی هستند که در حین محاسبه رخ میدهند. هر یک با یک پرچم زمینه و یک فعالساز تلهی زمینه متناظر است.
پرچم زمینه هرگاه که شرط رخ دهد تنظیم میشود. پس از محاسبه، پرچمها را میتوان برای اهداف اطلاعرسانی بررسی کرد (برای نمونه، برای تعیین اینکه آیا یک محاسبه دقیق بوده است). پس از بررسی پرچمها، حتماً همهی پرچمها را پیش از آغاز محاسبهی بعدی پاک کنید.
اگر فعالساز تلهی زمینه برای سیگنال تنظیم شده باشد، آنگاه شرط باعث پرتاب یک استثنای پایتون میشود. برای مثال، اگر تلهی DivisionByZero تنظیم شده باشد، هنگام مواجهه با شرط، یک استثنای DivisionByZero پرتاب میشود.
- class decimal.Clamped¶
توانی برای تطابق با محدودیتهای بازنمایی تغییر داده شد.
معمولاً، محدودسازی (clamping) زمانی رخ میدهد که یک توان خارج از محدودههای
EminوEmaxزمینه قرار گیرد. در صورت امکان، توان با افزودن صفر به ضریب کاهش مییابد تا در محدوده قرار گیرد.
- class decimal.DecimalException¶
کلاس پایه برای سایر سیگنالها و زیرکلاسی از
ArithmeticError.
- class decimal.DivisionByZero¶
نشاندهنده تقسیم یک عدد غیربینهایت بر صفر است.
ممکن است در تقسیم، تقسیم پیمانهای، یا هنگام رساندن یک عدد به توان منفی رخ دهد. اگر این سیگنال به دام نیفتد،
Infinityیا-Infinityرا با علامتی که توسط ورودیهای محاسبه تعیین میشود برمیگرداند.
- class decimal.Inexact¶
نشان میدهد که گرد کردن رخ داده است و نتیجه دقیق نیست.
سیگنال زمانی رخ میدهد که رقمهای غیرصفر در حین گرد کردن دور ریخته شوند. نتیجهی گرد شده بازگردانده میشود. پرچم سیگنال یا تله برای تشخیص زمانی که نتایج نادقیق هستند استفاده میشود.
- class decimal.InvalidOperation¶
یک عملیات نامعتبر انجام شد.
نشان میدهد که عملیاتی درخواست شده است که معنادار نیست. اگر تلهگذاری (trap) نشده باشد،
NaNرا برمیگرداند. علل احتمالی عبارتاند از:Infinity - Infinity 0 * Infinity Infinity / Infinity x % 0 Infinity % x sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) x ** Infinity
- class decimal.Overflow¶
سرریز عددی.
نشان میدهد که توان پس از انجام گرد کردن، بزرگتر از
Context.Emaxاست. اگر تلهگذاری نشده باشد، نتیجه به حالت گرد کردن بستگی دارد؛ یا به سمت داخل به بزرگترین عدد متناهی قابل نمایش کشیده میشود یا به سمت خارج بهInfinityگرد میشود. در هر صورت،InexactوRoundedنیز علامت داده میشوند.
- class decimal.Rounded¶
گرد کردن رخ داد، هرچند ممکن است اطلاعاتی از دست نرفته باشد.
این سیگنال هرگاه گرد کردن باعث حذف ارقامی شود، داده میشود؛ حتی اگر آن ارقام صفر باشند (مانند گرد کردن
5.00به5.0). اگر به دام نیفتد، نتیجه بدون تغییر برگردانده میشود. این سیگنال برای تشخیص از دست رفتن ارقام معنادار استفاده میشود.
- class decimal.Subnormal¶
توان پیش از گرد کردن کمتر از
Eminبود.هنگامی رخ میدهد که نتیجهی یک عملیات زیرنرمال باشد (توان بیش از حد کوچک باشد). اگر تله برای آن فعال نباشد، نتیجه بدون تغییر بازگردانده میشود.
- class decimal.Underflow¶
زیرریز عددی با نتیجهای که به صفر گرد شده است.
هنگامی رخ میدهد که یک نتیجه زیرنرمال بر اثر گرد کردن به صفر رانده شود.
InexactوSubnormalنیز سیگنال داده میشوند.
- class decimal.FloatOperation¶
فعالسازی معناشناسی سختگیرانهتر برای ترکیب اعداد اعشاری و Decimalها.
اگر سیگنال به دام نیفتد (پیشفرض)، ترکیب شناورها و Decimalها در سازندهی
Decimal،create_decimal()و تمام عملگرهای مقایسهای مجاز است. هم تبدیلها و هم مقایسهها دقیق هستند. هر بار وقوع یک عملیات مختلط، بهصورت خاموش با تنظیمFloatOperationدر پرچمهای زمینه ثبت میشود. تبدیلهای صریح باfrom_float()یاcreate_decimal_from_float()این پرچم را تنظیم نمیکنند.در غیر این صورت (سیگنال به دام افتاده است)، فقط مقایسههای برابری و تبدیلهای صریح بیصدا هستند. تمام عملیات مختلط دیگر
FloatOperationرا پرتاب میکنند.
جدول زیر سلسلهمراتب سیگنالها را خلاصه میکند:
exceptions.ArithmeticError(exceptions.Exception)
DecimalException
Clamped
DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
Inexact
Overflow(Inexact, Rounded)
Underflow(Inexact, Rounded, Subnormal)
InvalidOperation
Rounded
Subnormal
FloatOperation(DecimalException, exceptions.TypeError)
نکات مربوط به اعداد اعشاری¶
کاهش خطای گرد کردن با افزایش دقت¶
استفاده از ممیز شناور اعشاری، خطای بازنمایی اعشاری را برطرف میکند (و امکان بازنمایی دقیق 0.1 را ممکن میسازد)؛ با این حال، برخی عملیات هنوز ممکن است دچار خطای گرد کردن شوند، هنگامی که ارقام غیرصفر از دقت ثابت بیشتر شوند.
اثرات خطای گرد کردن میتواند با جمع یا تفریق کمیتهایی که تقریباً یکدیگر را خنثی میکنند، تشدید شود و به از دست رفتن ارقام معنادار بینجامد. کنوت دو مثال آموزنده ارائه میدهد که در آنها حساب ممیز شناور گردشده با دقت ناکافی باعث از کار افتادن ویژگیهای شرکتپذیری و توزیعپذیری جمع میشود:
# Examples from Seminumerical Algorithms, Section 4.2.2.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.5111111')
>>> u + (v + w)
Decimal('10')
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.01')
>>> u * (v+w)
Decimal('0.0060000')
ماژول decimal امکان برقراری مجدد اتحادها را با افزایش دقت بهاندازه کافی برای جلوگیری از از دست رفتن معناداری فراهم میکند:
>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.51111111')
>>> u + (v + w)
Decimal('9.51111111')
>>>
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.0060000')
>>> u * (v+w)
Decimal('0.0060000')
مقادیر خاص¶
سیستم اعداد ماژول decimal مقادیر ویژهای از جمله NaN، sNaN، -Infinity، Infinity و دو صفر، +0 و -0 را فراهم میکند.
بینهایتها را میتوان مستقیماً با Decimal('Infinity') ساخت. همچنین، آنها میتوانند در اثر تقسیم بر صفر، زمانی که سیگنال DivisionByZero به دام نیفتاده باشد، به وجود آیند. به همین ترتیب، زمانی که سیگنال Overflow به دام نیفتاده باشد، بینهایت میتواند در اثر گرد کردن فراتر از محدودهی بزرگترین عدد قابل نمایش حاصل شود.
بینهایتها علامتدار (affine) هستند و میتوان از آنها در عملیات حسابی استفاده کرد، که در آنها بهعنوان اعدادی بسیار بزرگ و نامعین در نظر گرفته میشوند. برای مثال، افزودن یک ثابت به بینهایت، نتیجهی بینهایت دیگری میدهد.
برخی عملیاتها نامعین هستند و NaN را برمیگردانند، یا اگر سیگنال InvalidOperation به دام افتاده باشد، استثنایی را پرتاب میکنند. برای مثال، 0/0 مقدار NaN را برمیگرداند که به معنای «عدد نیست» است. این نوع NaN ساکت است و پس از ایجاد، در دیگر محاسبات جریان مییابد و همیشه به NaN دیگری منجر میشود. این رفتار میتواند برای مجموعهای از محاسبات که گاهی ورودیهای ناموجود دارند مفید باشد — این امر اجازه میدهد محاسبه ادامه یابد، در حالی که نتایج خاصی را بهعنوان نامعتبر علامتگذاری میکند.
یکی از گونهها sNaN است که بهجای ساکت ماندن پس از هر عملیات، سیگنال میدهد. این مقدار بازگشتی مفیدی است، هنگامی که نیاز است یک نتیجه نامعتبر محاسبهای را برای مدیریت ویژه متوقف کند.
رفتار عملگرهای مقایسهای پایتون میتواند در مواردی که یک NaN در میان باشد، کمی غافلگیرکننده باشد. آزمون برابری در صورتی که یکی از عملوندها یک NaN ساکت یا سیگنالدهنده باشد، همیشه False برمیگرداند (حتی هنگام انجام Decimal('NaN')==Decimal('NaN'))، در حالی که آزمون نابرابری همیشه True برمیگرداند. تلاش برای مقایسهی دو Decimal با استفاده از هر یک از عملگرهای <، <=، > یا >=، در صورتی که یکی از عملوندها NaN باشد، سیگنال InvalidOperation را پرتاب میکند و اگر این سیگنال به دام نیفتد، False برمیگرداند. توجه داشته باشید که مشخصهی General Decimal Arithmetic رفتار مقایسههای مستقیم را تعیین نمیکند؛ این قواعد برای مقایسههای شامل یک NaN از استاندارد IEEE 854 گرفته شدهاند (جدول ۳ در بخش ۵.۷ را ببینید). برای اطمینان از انطباق دقیق با استانداردها، در عوض از متدهای compare() و compare_signal() استفاده کنید.
صفرهای علامتدار میتوانند از محاسباتی که دچار زیرریز (underflow) میشوند حاصل شوند. آنها علامتی را حفظ میکنند که اگر محاسبه با دقت بیشتری انجام میشد، حاصل میشد. از آنجا که بزرگی آنها صفر است، صفرهای مثبت و منفی هر دو برابر در نظر گرفته میشوند و علامت آنها صرفاً اطلاعرسانی است.
علاوه بر دو صفر علامتدار که متمایز اما برابر هستند، نمایشهای گوناگونی از صفر با دقتهای متفاوت اما همارز در مقدار وجود دارد. این موضوع کمی نیاز به عادت کردن دارد. برای چشمی که به نمایشهای نقطهشناور نرمالشده عادت کرده است، فوراً بدیهی نیست که محاسبهی زیر مقداری برابر با صفر برمیگرداند:
>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')
کار با نخها¶
تابع getcontext() برای هر نخ به یک شیء Context متفاوت دسترسی دارد. داشتن زمینههای جداگانه برای نخها به این معناست که نخها میتوانند تغییراتی (مانند getcontext().prec=10) بدون تداخل با سایر نخها ایجاد کنند.
به همین ترتیب، تابع setcontext() بهطور خودکار هدف خود را به نخ جاری اختصاص میدهد.
اگر setcontext() پیش از getcontext() فراخوانی نشده باشد، آنگاه getcontext() بهطور خودکار یک زمینه جدید برای استفاده در نخ جاری ایجاد میکند. اشیای زمینه جدید دارای مقادیر پیشفرضی هستند که از شیء decimal.DefaultContext تنظیم شدهاند.
پرچم sys.flags.thread_inherit_context بر زمینهی نخهای جدید تأثیر میگذارد. اگر پرچم نادرست باشد، نخهای جدید با یک زمینهی خالی آغاز میشوند. در این حالت، getcontext() هنگام فراخوانی یک شیء زمینهی جدید ایجاد میکند و از مقادیر پیشفرض DefaultContext استفاده میکند. اگر پرچم درست باشد، نخهای جدید با رونوشتی از زمینهی فراخوانندهی threading.Thread.start() آغاز میشوند.
برای کنترل پیشفرضها به گونهای که هر نخ در سراسر برنامه از مقادیر یکسانی استفاده کند، مستقیماً شیء DefaultContext را تغییر دهید. این کار باید پیش از شروع هر نخی انجام شود تا شرایط رقابتی بین نخهایی که getcontext() را فراخوانی میکنند، وجود نداشته باشد. برای مثال:
# Set applicationwide defaults for all threads about to be launched
DefaultContext.prec = 12
DefaultContext.rounding = ROUND_DOWN
DefaultContext.traps = ExtendedContext.traps.copy()
DefaultContext.traps[InvalidOperation] = 1
setcontext(DefaultContext)
# Afterwards, the threads can be started
t1.start()
t2.start()
t3.start()
. . .
دستورهای عملی¶
در ادامه چند راهحل آورده شده است که بهعنوان توابع سودمند به کار میروند و روشهایی برای کار با کلاس Decimal را نشان میدهند:
def moneyfmt(value, places=2, curr='', sep=',', dp='.',
pos='', neg='-', trailneg=''):
"""Convert Decimal to a money formatted string.
places: required number of places after the decimal point
curr: optional currency symbol before the sign (may be blank)
sep: optional grouping separator (comma, period, space, or blank)
dp: decimal point indicator (comma or period)
only specify as blank when places is zero
pos: optional sign for positive numbers: '+', space or blank
neg: optional sign for negative numbers: '-', '(', space or blank
trailneg:optional trailing minus indicator: '-', ')', space or blank
>>> d = Decimal('-1234567.8901')
>>> moneyfmt(d, curr='$')
'-$1,234,567.89'
>>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
'1.234.568-'
>>> moneyfmt(d, curr='$', neg='(', trailneg=')')
'($1,234,567.89)'
>>> moneyfmt(Decimal(123456789), sep=' ')
'123 456 789.00'
>>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
'<0.02>'
"""
q = Decimal(10) ** -places # 2 places --> '0.01'
sign, digits, exp = value.quantize(q).as_tuple()
result = []
digits = list(map(str, digits))
build, next = result.append, digits.pop
if sign:
build(trailneg)
for i in range(places):
build(next() if digits else '0')
if places:
build(dp)
if not digits:
build('0')
i = 0
while digits:
build(next())
i += 1
if i == 3 and digits:
i = 0
build(sep)
build(curr)
build(neg if sign else pos)
return ''.join(reversed(result))
def pi():
"""Compute Pi to the current precision.
>>> print(pi())
3.141592653589793238462643383
"""
getcontext().prec += 2 # extra digits for intermediate steps
three = Decimal(3) # substitute "three=3.0" for regular floats
lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
while s != lasts:
lasts = s
n, na = n+na, na+8
d, da = d+da, da+32
t = (t * n) / d
s += t
getcontext().prec -= 2
return +s # unary plus applies the new precision
def exp(x):
"""Return e raised to the power of x. Result type matches input type.
>>> print(exp(Decimal(1)))
2.718281828459045235360287471
>>> print(exp(Decimal(2)))
7.389056098930650227230427461
>>> print(exp(2.0))
7.38905609893
>>> print(exp(2+0j))
(7.38905609893+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num = 0, 0, 1, 1, 1
while s != lasts:
lasts = s
i += 1
fact *= i
num *= x
s += num / fact
getcontext().prec -= 2
return +s
def cos(x):
"""Return the cosine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(cos(Decimal('0.5')))
0.8775825618903727161162815826
>>> print(cos(0.5))
0.87758256189
>>> print(cos(0.5+0j))
(0.87758256189+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
def sin(x):
"""Return the sine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(sin(Decimal('0.5')))
0.4794255386042030002732879352
>>> print(sin(0.5))
0.479425538604
>>> print(sin(0.5+0j))
(0.479425538604+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
پرسشهای متداول دربارهی Decimal¶
پرسش: وارد کردن decimal.Decimal('1234.5') دشوار است. آیا راهی برای به حداقل رساندن میزان تایپ هنگام استفاده از مفسر تعاملی وجود دارد؟
پاسخ: برخی کاربران سازنده را فقط به یک حرف خلاصه میکنند:
>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')
پرسش: در یک برنامه ممیز ثابت با دو رقم اعشار، برخی ورودیها رقمهای اعشار زیادی دارند و باید گرد شوند. برخی دیگر نباید ارقام اضافی داشته باشند و باید اعتبارسنجی شوند. از چه متدهایی باید استفاده کرد؟
A: متد quantize() به تعداد ثابتی از رقمهای اعشاری گرد میکند. اگر تلهی Inexact تنظیم شده باشد، برای اعتبارسنجی نیز مفید است:
>>> TWOPLACES = Decimal(10) ** -2 # same as Decimal('0.01')
>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
>>> # Validate that a number does not exceed two places
>>> Decimal('3.21').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Decimal('3.21')
>>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Traceback (most recent call last):
...
Inexact: None
پ: هنگامی که ورودیهای معتبر با دو رقم اعشاری داشته باشم، چگونه میتوانم آن ناوردا را در سراسر یک برنامه حفظ کنم؟
پاسخ: برخی عملیات مانند جمع، تفریق و ضرب در یک عدد صحیح بهطور خودکار ممیز ثابت را حفظ میکنند. عملیات دیگر، مانند تقسیم و ضرب در عدد غیرصحیح، تعداد ارقام اعشار را تغییر میدهند و باید پس از آنها یک مرحله quantize() انجام شود:
>>> a = Decimal('102.72') # Initial fixed-point values
>>> b = Decimal('3.17')
>>> a + b # Addition preserves fixed-point
Decimal('105.89')
>>> a - b
Decimal('99.55')
>>> a * 42 # So does integer multiplication
Decimal('4314.24')
>>> (a * b).quantize(TWOPLACES) # Must quantize non-integer multiplication
Decimal('325.62')
>>> (b / a).quantize(TWOPLACES) # And quantize division
Decimal('0.03')
در توسعهی برنامههای ممیز ثابت، تعریف توابع برای مدیریت مرحلهی quantize() مطلوب است:
>>> def mul(x, y, fp=TWOPLACES):
... return (x * y).quantize(fp)
...
>>> def div(x, y, fp=TWOPLACES):
... return (x / y).quantize(fp)
>>> mul(a, b) # Automatically preserve fixed-point
Decimal('325.62')
>>> div(b, a)
Decimal('0.03')
پرسش: راههای زیادی برای بیان یک مقدار یکسان وجود دارد. اعداد 200، 200.000، 2E2 و .02E+4 همگی در دقتهای مختلف مقدار یکسانی دارند. آیا راهی برای تبدیل آنها به یک مقدار کانونیکال واحد و قابلتشخیص وجود دارد؟
پاسخ: متد normalize() تمام مقادیر همارز را به یک نمایندهی واحد نگاشت میکند:
>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split())
>>> [v.normalize() for v in values]
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]
پ: گرد کردن در یک محاسبه چه زمانی رخ میدهد؟
پاسخ: این امر پس از محاسبه رخ میدهد. فلسفهی مشخصات decimal این است که اعداد دقیق فرض میشوند و مستقل از زمینهی جاری ایجاد میشوند. حتی میتوانند دقتی بیشتر از زمینهی جاری داشته باشند. محاسبات با آن ورودیهای دقیق انجام میشوند و سپس گرد کردن (یا سایر عملیات زمینه) به نتیجهی محاسبه اعمال میشود:
>>> getcontext().prec = 5
>>> pi = Decimal('3.1415926535') # More than 5 digits
>>> pi # All digits are retained
Decimal('3.1415926535')
>>> pi + 0 # Rounded after an addition
Decimal('3.1416')
>>> pi - Decimal('0.00005') # Subtract unrounded numbers, then round
Decimal('3.1415')
>>> pi + 0 - Decimal('0.00005'). # Intermediate values are rounded
Decimal('3.1416')
پرسش: برخی مقادیر اعشاری همیشه با نماد نمایی چاپ میشوند. آیا راهی برای دریافت نمایش غیرنمایی وجود دارد؟
پاسخ: برای برخی از مقدارها، نماد نمایی تنها راه بیان تعداد ارقام معنادار در ضریب است. برای مثال، بیان 5.0E+3 بهصورت 5000 مقدار را ثابت نگه میدارد، اما نمیتواند نشان دهد که مقدار اصلی دو رقم معنادار دارد.
اگر برنامهای به پیگیری ارقام معنادار اهمیتی نمیدهد، میتوان بهراحتی توان و صفرهای انتهایی را حذف کرد؛ با این کار ارقام معنادار از دست میروند، اما مقدار بدون تغییر میماند:
>>> def remove_exponent(d):
... return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')
پرسش: آیا راهی برای تبدیل یک عدد اعشاری معمولی به Decimal وجود دارد؟
پ: بله، هر عدد ممیز شناور دودویی را میتوان دقیقاً بهصورت یک Decimal بیان کرد، هرچند یک تبدیل دقیق ممکن است به دقت بیشتری نسبت به آنچه بهطور شهودی انتظار میرود نیاز داشته باشد:
>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')
پرسش: در یک محاسبهی پیچیده، چگونه میتوانم مطمئن شوم که به دلیل دقت ناکافی یا ناهنجاریهای گردکردن، نتیجهای کاذب به دست نیاوردهام.
پاسخ: ماژول decimal آزمایش نتایج را آسان میکند. بهترین روش این است که محاسبات را با دقت بیشتر و با حالتهای مختلف گرد کردن دوباره اجرا کنید. نتایج بسیار متفاوت، دقت ناکافی، مشکلات مربوط به حالت گرد کردن، ورودیهای بدشرط یا یک الگوریتم ناپایدار عددی را نشان میدهند.
پرسش: متوجه شدهام که دقت زمینه بر نتایج عملیات اعمال میشود، اما نه بر ورودیها. آیا هنگام ترکیب مقادیر با دقتهای مختلف، نکتهای وجود دارد که باید به آن توجه کنید؟
پاسخ: بله. اصل این است که همه مقادیر دقیق در نظر گرفته میشوند و عملیات حسابی روی آن مقادیر نیز دقیق است. فقط نتایج گرد میشوند. مزیت آن برای ورودیها این است که «آنچه تایپ میکنید، همان را دریافت میکنید». عیب آن این است که اگر فراموش کنید ورودیها گرد نشدهاند، نتایج ممکن است عجیب به نظر برسند:
>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')
راهحل یا افزایش دقت است یا گرد کردن اجباری ورودیها با استفاده از عملیات مثبت یکعملوندی:
>>> getcontext().prec = 3
>>> +Decimal('1.23456789') # unary plus triggers rounding
Decimal('1.23')
بهعنوان جایگزین، ورودیها میتوانند در زمان ایجاد با استفاده از متد Context.create_decimal() گرد شوند:
>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')
پرسش: آیا پیادهسازی CPython برای اعداد بزرگ سریع است؟
پاسخ: بله. در پیادهسازیهای CPython و PyPy3، نسخههای C/CFFI ماژول decimal از کتابخانه پرسرعت libmpdec برای حساب ممیز شناور اعشاری با دقت دلخواه و گردکردن صحیح بهره میبرند [1]. libmpdec برای اعداد با اندازه متوسط از ضرب کاراتسوبا و برای اعداد بسیار بزرگ از تبدیل نظریهای اعداد (Number Theoretic Transform) استفاده میکند.
زمینه باید برای عملیات حسابی دقیق با دقت دلخواه تطبیق داده شود. Emin و Emax باید همیشه روی مقادیر بیشینه تنظیم شوند، clamp باید همیشه ۰ (پیشفرض) باشد. تنظیم prec به کمی دقت نیاز دارد.
سادهترین روش برای آزمایش حساب اعداد بزرگ (bignum arithmetic) این است که از حداکثر مقدار prec نیز استفاده کنید [2]:
>>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))
>>> x = Decimal(2) ** 256
>>> x / 128
Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')
برای نتایج غیردقیق، MAX_PREC در پلتفرمهای ۶۴ بیتی بسیار بیشازحد بزرگ است و حافظهی در دسترس کافی نخواهد بود:
>>> Decimal(1) / 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
MemoryError
در سیستمهایی با تخصیص بیشازحد (overallocation)، مانند لینوکس، رویکرد پیشرفتهتر این است که prec را متناسب با مقدار RAM در دسترس تنظیم کنید. فرض کنید ۸ گیگابایت RAM دارید و انتظار ۱۰ عملوند همزمان را دارید که هرکدام حداکثر ۵۰۰ مگابایت مصرف میکنند:
>>> import sys
>>>
>>> # Maximum number of digits for a single operand using 500MB in 8-byte words
>>> # with 19 digits per word (4-byte and 9 digits for the 32-bit build):
>>> maxdigits = 19 * ((500 * 1024**2) // 8)
>>>
>>> # Check that this works:
>>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN)
>>> c.traps[Inexact] = True
>>> setcontext(c)
>>>
>>> # Fill the available precision with nines:
>>> x = Decimal(0).logical_invert() * 9
>>> sys.getsizeof(x)
524288112
>>> x + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.Inexact: [<class 'decimal.Inexact'>]
بهطور کلی (و بهویژه در سیستمهای بدون تخصیص بیشازحد (overallocation))، توصیه میشود کرانهای حتی محدودتری را برآورد کنید و اگر انتظار میرود همهی محاسبات دقیق باشند، تلهی Inexact را تنظیم کنید.