十进制胶囊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_TypeCheck(const PyObject *dec)

返回1如果 dec 为十进制,否则为0。此函数不设置任何异常。

int PyDec_IsSpecial(const PyObject *dec)

返回1如果 decNaNsNaNInfinity ,否则为0。

设置TypeError并返回-1 if dec 不是十进制。可以保证这是唯一的故障模式,因此如果 dec 已进行类型检查,不会出现错误,并且可以将函数视为简单谓词。

int PyDec_IsNaN(const PyObject *dec)

返回1如果 decNaNsNaN ,否则为0。

设置TypeError并返回-1 if dec 不是十进制。可以保证这是唯一的故障模式,因此如果 dec 已进行类型检查,不会出现错误,并且可以将函数视为简单谓词。

int PyDec_IsInfinite(const PyObject *dec)

返回1如果 decInfinity ,否则为0。

设置TypeError并返回-1 if dec 不是十进制。可以保证这是唯一的故障模式,因此如果 dec 已进行类型检查,不会出现错误,并且可以将函数视为简单谓词。

int64_t PyDec_GetDigits(const PyObject *dec)

返回系数中的位数。为 Infinity ,位数始终为零。通常情况下,这同样适用于 NaNsNaN ,但这两个都可以有一个等效于系数的有效载荷。因此, NaNs 返回值不能为零。

设置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)是一个既定的术语,并且 (hilo )表示单个 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)

从三元组创建十进制数。初始化三元组时必须遵守以下规则:

  1. triple.sign 必须始终为0(表示正)或1(表示负)。

  2. MPD_TRIPLE_QNANtriple.exp 必须是0。如果 triple.hitriple.lo 非零,创建一个 NaN 有效载荷。

  3. MPD_TRIPLE_SNANtriple.exp 必须是0。如果 triple.hitriple.lo 非零,创建一个 sNaN 有效载荷。

  4. MPD_TRIPLE_INFtriple.exptriple.hitriple.lo 必须是零。

  5. MPD_TRIPLE_NORMALMPD_MIN_ETINY + 38 < triple.exp < MPD_MAX_EMAX - 38 . triple.hitriple.lo 可以自由选择。

  6. MPD_TRIPLE_ERROR :设置此标记总是错误的。

如果不满足上述条件之一,函数将返回 NaN 如果 InvalidOperation 线程本地上下文中未设置陷阱。否则,它将设置 InvalidOperation 异常并返回NULL。

此外,虽然不太可能给出较小的分配大小,但函数可以设置 MemoryError 然后返回 NULL .

高级API

此API允许使用 libmpdec 功能。因为Python是用隐藏符号编译的,所以API需要一个外部libmpdec和 mpdecimal.h 标题。

功能

PyObject *PyDec_Alloc(void)

返回可在 result 位置 libmpdec 功能。

mpd_t *PyDec_Get(PyObject *v)

获取指向内部 mpd_t 十进制的。小数是不可变的,因此此函数只能用于由PyDec_Alloc()创建的新小数。

const mpd_t *PyDec_GetConst(const PyObject *v)

获取指向内部常量的指针 mpd_t 十进制的。