十进制胶囊API¶
只要API已经初始化,就可以以与常规库函数相同的方式使用capsuleapi函数。
初始化¶
通常,使用decimal API的C扩展模块将在其init函数中执行以下步骤:
#include "pydecimal.h"
static int decimal_initialized = 0;
if (!decimal_initialized) {
if (import_decimal() < 0) {
return NULL;
}
decimal_initialized = 1;
}
类型检查、谓词、访问器¶
-
int PyDec_IsSpecial(const PyObject *dec)¶
返回1如果
dec
是NaN
,sNaN
或Infinity
,否则为0。设置TypeError并返回-1 if
dec
不是十进制。可以保证这是唯一的故障模式,因此如果dec
已进行类型检查,不会出现错误,并且可以将函数视为简单谓词。
-
int PyDec_IsNaN(const PyObject *dec)¶
返回1如果
dec
是NaN
或sNaN
,否则为0。设置TypeError并返回-1 if
dec
不是十进制。可以保证这是唯一的故障模式,因此如果dec
已进行类型检查,不会出现错误,并且可以将函数视为简单谓词。
小数与本原C类型的精确转换¶
此API支持系数高达38位的小数的转换。
数据结构¶
转换函数使用以下状态代码和数据结构:
/* status cases for getting a triple */
enum mpd_triple_class {
MPD_TRIPLE_NORMAL,
MPD_TRIPLE_INF,
MPD_TRIPLE_QNAN,
MPD_TRIPLE_SNAN,
MPD_TRIPLE_ERROR,
};
typedef struct {
enum mpd_triple_class tag;
uint8_t sign;
uint64_t hi;
uint64_t lo;
int64_t exp;
} mpd_uint128_triple_t;
状态案例解释如下。 sign
0表示正,1表示负。 ((uint128_t)hi << 64) + lo
是系数, exp
是指数。
数据结构被称为“三元组”,因为十进制三元组(sign、coeff、exp)是一个既定的术语,并且 (hi
, lo
)表示单个 uint128_t
系数。
功能¶
-
mpd_uint128_triple_t PyDec_AsUint128Triple(const PyObject *dec)¶
把十进制数转换成三元组。如上所述,可以保证Python唯一的失败模式是TypeError,如果知道类型,则可以省略检查。
为了简单起见,函数的用法和所有特殊情况都以代码形式和注释进行了说明:
triple = PyDec_AsUint128Triple(dec);
switch (triple.tag) {
case MPD_TRIPLE_QNAN:
/*
* Success: handle a quiet NaN.
* 1) triple.sign is 0 or 1.
* 2) triple.exp is always 0.
* 3) If triple.hi or triple.lo are nonzero, the NaN has a payload.
*/
break;
case MPD_TRIPLE_SNAN:
/*
* Success: handle a signaling NaN.
* 1) triple.sign is 0 or 1.
* 2) triple.exp is always 0.
* 3) If triple.hi or triple.lo are nonzero, the sNaN has a payload.
*/
break;
case MPD_TRIPLE_INF:
/*
* Success: handle Infinity.
* 1) triple.sign is 0 or 1.
* 2) triple.exp is always 0.
* 3) triple.hi and triple.lo are always zero.
*/
break;
case MPD_TRIPLE_NORMAL:
/* Success: handle a finite value. */
break;
case MPD_TRIPLE_ERROR:
/* TypeError check: can be omitted if the type of dec is known. */
if (PyErr_Occurred()) {
return NULL;
}
/* Too large for conversion. PyDec_AsUint128Triple() does not set an
exception so applications can choose themselves. Typically this
would be a ValueError. */
PyErr_SetString(PyExc_ValueError,
"value out of bounds for a uint128 triple");
return NULL;
}
-
PyObject *PyDec_FromUint128Triple(const mpd_uint128_triple_t *triple)¶
从三元组创建十进制数。初始化三元组时必须遵守以下规则:
triple.sign
必须始终为0(表示正)或1(表示负)。MPD_TRIPLE_QNAN
:triple.exp
必须是0。如果triple.hi
或triple.lo
非零,创建一个NaN
有效载荷。MPD_TRIPLE_SNAN
:triple.exp
必须是0。如果triple.hi
或triple.lo
非零,创建一个sNaN
有效载荷。MPD_TRIPLE_INF
:triple.exp
,triple.hi
和triple.lo
必须是零。MPD_TRIPLE_NORMAL
:MPD_MIN_ETINY + 38 < triple.exp < MPD_MAX_EMAX - 38
.triple.hi
和triple.lo
可以自由选择。MPD_TRIPLE_ERROR
:设置此标记总是错误的。
如果不满足上述条件之一,函数将返回
NaN
如果InvalidOperation
线程本地上下文中未设置陷阱。否则,它将设置InvalidOperation
异常并返回NULL。此外,虽然不太可能给出较小的分配大小,但函数可以设置
MemoryError
然后返回NULL
.
高级API¶
此API允许使用 libmpdec
功能。因为Python是用隐藏符号编译的,所以API需要一个外部libmpdec和 mpdecimal.h
标题。