Assignment, Conversions, I/O

Create Decimal

From String

void mpd_qset_string(mpd_t *result, const char *s, const mpd_context_t *ctx,
                     uint32_t *status);
void mpd_set_string(mpd_t *result, const char *s, mpd_context_t *ctx);

Set result from s. The context is respected. This means that rounding, overflow etc. can take place. If the string is not valid, the MPD_Conversion_syntax condition is added to status and result is set to NaN.

void mpd_qset_string_exact(mpd_t *result, const char *s, uint32_t *status);

Set result from s. The conversion is exact. If internal limits prevent exact conversion, the MPD_Invalid_operation condition is added to status and result is set to NaN.

New in version 2.5.0.

From Integer

void mpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx,
                    uint32_t *status);
void mpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx,
                  uint32_t *status);
void mpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx,
                  uint32_t *status);
void mpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx,
                   uint32_t *status);
void mpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx,
                  uint32_t *status);
void mpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx,
                  uint32_t *status);

void mpd_set_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx);
void mpd_set_i32(mpd_t *result, int32_t a, mpd_context_t *ctx);
void mpd_set_i64(mpd_t *result, int64_t a, mpd_context_t *ctx);
void mpd_set_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx);
void mpd_set_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx);
void mpd_set_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx);

Set result from a C integer type. The context is respected.

void mpd_qset_i64_exact(mpd_t *result, int64_t a, uint32_t *status);
void mpd_qset_u64_exact(mpd_t *result, uint64_t a, uint32_t *status);

Set result from a C integer type. The conversion is exact. If exact conversion is not possible, the MPD_Invalid_operation condition is added to status and result is set to NaN.

New in version 2.5.0.

From Special Values

void mpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status);

Set result to NaN, with the error condition passed in flags. The error condition is added to status. This is a convenience function intended to be used inside quiet functions.

void mpd_setspecial(mpd_t *result, uint8_t sign, uint8_t type);

Set result to a special number. sign must be one of {MPD_POS, MPD_NEG}, type one of {MPD_INF, MPD_NAN, MPD_SNAN}.

void mpd_zerocoeff(mpd_t *result);

Set the coefficient of result to zero. This function cannot fail.

void mpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx,
                   uint32_t *status);
void mpd_maxcoeff(mpd_t *result, mpd_context_t *ctx);

Set the coefficient of result to the maximum value allowed by ctx->prec. The function can fail with MPD_Malloc_error.

From 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;  /* 0 for positive and 1 for negative */
  uint64_t hi;   /* ((uint128_t)hi << 64) + lo is the coefficient */
  uint64_t lo;
  int64_t exp;   /* exponent */
} mpd_uint128_triple_t;

int mpd_from_uint128_triple(mpd_t *result, const mpd_uint128_triple_t *triple, uint32_t *status);

Create a decimal from a triple. The following rules must be observed for initializing the triple:

  • sign must always be 0 (for positive) or 1 (for negative).

  • MPD_TRIPLE_QNAN: exp must be 0. If hi or lo are nonzero, create a NaN with a payload.

  • MPD_TRIPLE_SNAN: exp must be 0. If hi or lo are nonzero, create an sNaN with a payload.

  • MPD_TRIPLE_INF: exp, hi and lo must be zero.

  • MPD_TRIPLE_NORMAL: MPD_MIN_ETINY + 38 < exp < MPD_MAX_EMAX - 38. hi and lo can be chosen freely.

  • MPD_TRIPLE_ERROR: It is always an error to set this tag.

If one of the above conditions is not met, the function sets MPD_Invalid_operation and result is NaN.

Additionally, though extremely unlikely given the small allocation sizes, the function can set MPD_Malloc_error.

New in version 2.5.1.

Create Static Decimal

From Integer

void mpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx,
                     uint32_t *status);
void mpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx,
                   uint32_t *status);
void mpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx,
                    uint32_t *status);
void mpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx,
                   uint32_t *status);

void mpd_sset_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx);
void mpd_sset_i32(mpd_t *result, int32_t a, mpd_context_t *ctx);
void mpd_sset_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx);
void mpd_sset_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx);

/* 64-bit build only */
void mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx,
                   uint32_t *status);
void mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx,
                   uint32_t *status);

void mpd_sset_i64(mpd_t *result, int64_t a, mpd_context_t *ctx);
void mpd_sset_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx);

Set result from a C integer type. The context is respected. result must be a static decimal, see section Advanced Memory Handling.

Convert Decimal

To String

char *mpd_to_sci(const mpd_t *dec, int fmt);
char *mpd_to_eng(const mpd_t *dec, int fmt);

mpd_ssize_t mpd_to_sci_size(char **res, const mpd_t *dec, int fmt);
mpd_ssize_t mpd_to_eng_size(char **res, const mpd_t *dec, int fmt);

Return the scientific or engineering string representation of a decimal. This operation is not context sensitive. If fmt is zero, the exponent character is lower case, otherwise it is upper case. If allocating memory for the string fails, NULL is returned.

New in version 2.4.0: mpd_to_sci_size and mpd_to_eng_size additionally return the size of the result string, without counting the terminating NUL. The goal is to avoid an unnecessary call to strlen.

char *mpd_qformat(const mpd_t *dec, const char *fmt,
                  const mpd_context_t *ctx, uint32_t *status);
char *mpd_format(const mpd_t *dec, const char *fmt,
                 mpd_context_t *ctx);

Return the string representation of a decimal according to format string fmt. The format string syntax is the same as in Python PEP 3101 (See Standard Format Specifiers) and is quite similar to the syntax used for floating point numbers the C fprintf function. The fill character may be a UTF-8 character, the rest of the format string must be ASCII.

The function can fail with MPD_Invalid_operation for an invalid format string or MPD_Malloc_error. In both cases, the return value is NULL.

If the “n” format specifier is used, the function calls localeconv.

Two cases must be considered:

  1. The locale is set at the start of the program and does not change. In this case, calls to localeconv should be thread-safe.

  2. setlocale is called after threads are started. In this case, depending on the guarantees of the system’s localeconv, the entire sequence of setlocale and mpd_qformat requires a lock.

All other format specifiers are thread-safe.

New in version 4.0.0: Support for the “z” format specifier, which coerces negative zeros to positive.

To Integer

mpd_ssize_t mpd_qget_ssize(const mpd_t *dec, uint32_t *status);
mpd_uint_t mpd_qget_uint(const mpd_t *dec, uint32_t *status);
mpd_ssize_t mpd_get_ssize(const mpd_t *a, mpd_context_t *ctx);
mpd_uint_t mpd_get_uint(const mpd_t *a, mpd_context_t *ctx);

int32_t mpd_qget_i32(const mpd_t *a, uint32_t *status);
uint32_t mpd_qget_u32(const mpd_t *a, uint32_t *status);
int32_t mpd_get_i32(const mpd_t *a, mpd_context_t *ctx);
uint32_t mpd_get_u32(const mpd_t *a, mpd_context_t *ctx);

uint64_t mpd_qget_u64(const mpd_t *dec, uint32_t *status);
int64_t mpd_qget_i64(const mpd_t *dec, uint32_t *status);
int64_t mpd_get_i64(const mpd_t *a, mpd_context_t *ctx);
uint64_t mpd_get_u64(const mpd_t *a, mpd_context_t *ctx);

Convert a decimal to a C integer type. If the decimal is not an integer or its value is outside the range of the C type, MPD_SSIZE_MAX is returned for signed types and MPD_UINT_MAX for unsigned types. In this case, the status is set to MPD_Invalid_operation. Since a decimal can have the values MPD_SSIZE_MAX or MPD_UINT_MAX, the only reliable way to check for errors is to check the status.

mpd_uint_t mpd_qabs_uint(const mpd_t *dec, uint32_t *status);
mpd_uint_t mpd_abs_uint(const mpd_t *a, mpd_context_t *ctx);

Return the absolute of numbers in the range [-MPD_UINT_MAX, MPD_UINT_MAX]. Error handling as above.

New in version 2.4.0: All functions are available in both the 64-bit and the 32-bit builds.

To 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;  /* 0 for positive and 1 for negative */
  uint64_t hi;   /* ((uint128_t)hi << 64) + lo is the coefficient */
  uint64_t lo;
  int64_t exp;   /* exponent */
} mpd_uint128_triple_t;

mpd_uint128_triple_t mpd_as_uint128_triple(const mpd_t *a);

Convert a decimal with up to 38 decimal digits to a triple.

For simplicity, the usage of the function and all special cases are explained in code form and comments:

triple = mpd_as_uint128_triple(dec);
switch (triple.tag) {
case MPD_TRIPLE_QNAN:
    /*
     * Success: handle a quiet NaN.
     *   1) sign is 0 or 1.
     *   2) exp is always 0.
     *   3) If hi or lo are nonzero, the NaN has a payload.
     */
    break;

case MPD_TRIPLE_SNAN:
    /*
     * Success: handle a signaling NaN.
     *   1) sign is 0 or 1.
     *   2) exp is always 0.
     *   3) If hi or lo are nonzero, the sNaN has a payload.
     */
    break;

case MPD_TRIPLE_INF:
    /*
     * Success: handle Infinity.
     *   1) sign is 0 or 1.
     *   2) exp is always 0.
     *   3) hi and lo are always zero.
     */
    break;

case MPD_TRIPLE_NORMAL:
    /* Success: handle a finite value. */
    break;

case MPD_TRIPLE_ERROR:
    /* The coefficient is too large for conversion. Handle the error. */
    break;
}

New in version 2.5.1.

Copy Decimal

int mpd_qcopy(mpd_t *result, const mpd_t *a,  uint32_t *status);
void mpd_copy(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);

Set result to the value of a and return 1 for success. On failure, return 0 and add MPD_Malloc_error to status.

mpd_t *mpd_qncopy(const mpd_t *a);

Return a pointer to a fresh copy of a, NULL on failure.

int mpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status);
void mpd_copy_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);

Set result to the value of a with the sign set to 0. If successful, return 1. Otherwise, return 0 and add MPD_Malloc_error to status.

int mpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status);
void mpd_copy_negate(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);

Set result to the value of a with the sign inverted. If successful, return 1. Otherwise, return 0 and add MPD_Malloc_error to status.

int mpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b,
                   uint32_t *status);
void mpd_copy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b,
                   mpd_context_t *ctx);

Set result to the value of a, using the sign of b. If successful, return 1. Otherwise, return 0 and add MPD_Malloc_error to status.