Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/intl/icu/source/i18n/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 397 kB image not shown  

Quelle  decNumber.cpp   Sprache: C

 
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/* ------------------------------------------------------------------ */
/* Decimal Number arithmetic module                                   */
/* ------------------------------------------------------------------ */
/* Copyright (c) IBM Corporation, 2000-2014.  All rights reserved.    */
/*                                                                    */
/* This software is made available under the terms of the             */
/* ICU License -- ICU 1.8.1 and later.                                */
/*                                                                    */
/* The description and User's Guide ("The decNumber C Library") for   */
/* this software is called decNumber.pdf.  This document is           */
/* available, together with arithmetic and format specifications,     */
/* testcases, and Web links, on the General Decimal Arithmetic page.  */
/*                                                                    */
/* Please send comments, suggestions, and corrections to the author:  */
/*   mfc@uk.ibm.com                                                   */
/*   Mike Cowlishaw, IBM Fellow                                       */
/*   IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK         */
/* ------------------------------------------------------------------ */

/* Modified version, for use from within ICU.
 *    Renamed public functions, to avoid an unwanted export of the 
 *    standard names from the ICU library.
 *
 *    Use ICU's uprv_malloc() and uprv_free()
 *
 *    Revert comment syntax to plain C
 *
 *    Remove a few compiler warnings.
 */


/* This module comprises the routines for arbitrary-precision General */
/* Decimal Arithmetic as defined in the specification which may be    */
/* found on the General Decimal Arithmetic pages.  It implements both */
/* the full ('extended') arithmetic and the simpler ('subset')        */
/* arithmetic.                                                        */
/*                                                                    */
/* Usage notes:                                                       */
/*                                                                    */
/* 1. This code is ANSI C89 except:                                   */
/*                                                                    */
/*    a) C99 line comments (double forward slash) are used.  (Most C  */
/*       compilers accept these.  If yours does not, a simple script  */
/*       can be used to convert them to ANSI C comments.)             */
/*                                                                    */
/*    b) Types from C99 stdint.h are used.  If you do not have this   */
/*       header file, see the User's Guide section of the decNumber   */
/*       documentation; this lists the necessary definitions.         */
/*                                                                    */
/*    c) If DECDPUN>4 or DECUSE64=1, the C99 64-bit int64_t and       */
/*       uint64_t types may be used.  To avoid these, set DECUSE64=0  */
/*       and DECDPUN<=4 (see documentation).                          */
/*                                                                    */
/*    The code also conforms to C99 restrictions; in particular,      */
/*    strict aliasing rules are observed.                             */
/*                                                                    */
/* 2. The decNumber format which this library uses is optimized for   */
/*    efficient processing of relatively short numbers; in particular */
/*    it allows the use of fixed sized structures and minimizes copy  */
/*    and move operations.  It does, however, support arbitrary       */
/*    precision (up to 999,999,999 digits) and arbitrary exponent     */
/*    range (Emax in the range 0 through 999,999,999 and Emin in the  */
/*    range -999,999,999 through 0).  Mathematical functions (for     */
/*    example decNumberExp) as identified below are restricted more   */
/*    tightly: digits, emax, and -emin in the context must be <=      */
/*    DEC_MAX_MATH (999999), and their operand(s) must be within      */
/*    these bounds.                                                   */
/*                                                                    */
/* 3. Logical functions are further restricted; their operands must   */
/*    be finite, positive, have an exponent of zero, and all digits   */
/*    must be either 0 or 1.  The result will only contain digits     */
/*    which are 0 or 1 (and will have exponent=0 and a sign of 0).    */
/*                                                                    */
/* 4. Operands to operator functions are never modified unless they   */
/*    are also specified to be the result number (which is always     */
/*    permitted).  Other than that case, operands must not overlap.   */
/*                                                                    */
/* 5. Error handling: the type of the error is ORed into the status   */
/*    flags in the current context (decContext structure).  The       */
/*    SIGFPE signal is then raised if the corresponding trap-enabler  */
/*    flag in the decContext is set (is 1).                           */
/*                                                                    */
/*    It is the responsibility of the caller to clear the status      */
/*    flags as required.                                              */
/*                                                                    */
/*    The result of any routine which returns a number will always    */
/*    be a valid number (which may be a special value, such as an     */
/*    Infinity or NaN).                                               */
/*                                                                    */
/* 6. The decNumber format is not an exchangeable concrete            */
/*    representation as it comprises fields which may be machine-     */
/*    dependent (packed or unpacked, or special length, for example). */
/*    Canonical conversions to and from strings are provided; other   */
/*    conversions are available in separate modules.                  */
/*                                                                    */
/* 7. Normally, input operands are assumed to be valid.  Set DECCHECK */
/*    to 1 for extended operand checking (including nullptr operands).   */
/*    Results are undefined if a badly-formed structure (or a nullptr    */
/*    pointer to a structure) is provided, though with DECCHECK       */
/*    enabled the operator routines are protected against exceptions. */
/*    (Except if the result pointer is nullptr, which is unrecoverable.) */
/*                                                                    */
/*    However, the routines will never cause exceptions if they are   */
/*    given well-formed operands, even if the value of the operands   */
/*    is inappropriate for the operation and DECCHECK is not set.     */
/*    (Except for SIGFPE, as and where documented.)                   */
/*                                                                    */
/* 8. Subset arithmetic is available only if DECSUBSET is set to 1.   */
/* ------------------------------------------------------------------ */
/* Implementation notes for maintenance of this module:               */
/*                                                                    */
/* 1. Storage leak protection:  Routines which use malloc are not     */
/*    permitted to use return for fastpath or error exits (i.e.,      */
/*    they follow strict structured programming conventions).         */
/*    Instead they have a do{}while(0); construct surrounding the     */
/*    code which is protected -- break may be used to exit this.      */
/*    Other routines can safely use the return statement inline.      */
/*                                                                    */
/*    Storage leak accounting can be enabled using DECALLOC.          */
/*                                                                    */
/* 2. All loops use the for(;;) construct.  Any do construct does     */
/*    not loop; it is for allocation protection as just described.    */
/*                                                                    */
/* 3. Setting status in the context must always be the very last      */
/*    action in a routine, as non-0 status may raise a trap and hence */
/*    the call to set status may not return (if the handler uses long */
/*    jump).  Therefore all cleanup must be done first.  In general,  */
/*    to achieve this status is accumulated and is only applied just  */
/*    before return by calling decContextSetStatus (via decStatus).   */
/*                                                                    */
/*    Routines which allocate storage cannot, in general, use the     */
/*    'top level' routines which could cause a non-returning          */
/*    transfer of control.  The decXxxxOp routines are safe (do not   */
/*    call decStatus even if traps are set in the context) and should */
/*    be used instead (they are also a little faster).                */
/*                                                                    */
/* 4. Exponent checking is minimized by allowing the exponent to      */
/*    grow outside its limits during calculations, provided that      */
/*    the decFinalize function is called later.  Multiplication and   */
/*    division, and intermediate calculations in exponentiation,      */
/*    require more careful checks because of the risk of 31-bit       */
/*    overflow (the most negative valid exponent is -1999999997, for  */
/*    a 999999999-digit number with adjusted exponent of -999999999). */
/*                                                                    */
/* 5. Rounding is deferred until finalization of results, with any    */
/*    'off to the right' data being represented as a single digit     */
/*    residue (in the range -1 through 9).  This avoids any double-   */
/*    rounding when more than one shortening takes place (for         */
/*    example, when a result is subnormal).                           */
/*                                                                    */
/* 6. The digits count is allowed to rise to a multiple of DECDPUN    */
/*    during many operations, so whole Units are handled and exact    */
/*    accounting of digits is not needed.  The correct digits value   */
/*    is found by decGetDigits, which accounts for leading zeros.     */
/*    This must be called before any rounding if the number of digits */
/*    is not known exactly.                                           */
/*                                                                    */
/* 7. The multiply-by-reciprocal 'trick' is used for partitioning     */
/*    numbers up to four digits, using appropriate constants.  This   */
/*    is not useful for longer numbers because overflow of 32 bits    */
/*    would lead to 4 multiplies, which is almost as expensive as     */
/*    a divide (unless a floating-point or 64-bit multiply is         */
/*    assumed to be available).                                       */
/*                                                                    */
/* 8. Unusual abbreviations that may be used in the commentary:       */
/*      lhs -- left hand side (operand, of an operation)              */
/*      lsd -- least significant digit (of coefficient)               */
/*      lsu -- least significant Unit (of coefficient)                */
/*      msd -- most significant digit (of coefficient)                */
/*      msi -- most significant item (in an array)                    */
/*      msu -- most significant Unit (of coefficient)                 */
/*      rhs -- right hand side (operand, of an operation)             */
/*      +ve -- positive                                               */
/*      -ve -- negative                                               */
/*      **  -- raise to the power                                     */
/* ------------------------------------------------------------------ */

#include <stdlib.h>                /* for malloc, free, etc.  */
/*  #include <stdio.h>   */        /* for printf [if needed]  */
#include <string.h>                /* for strcpy  */
#include <ctype.h>                 /* for lower  */
#include "cmemory.h"               /* for uprv_malloc, etc., in ICU */
#include "decNumber.h"             /* base number library  */
#include "decNumberLocal.h"        /* decNumber local types, etc.  */
#include "uassert.h"

/* Constants */
/* Public lookup table used by the D2U macro  */
static const uByte d2utable[DECMAXD2U+1]=D2UTABLE;

#define DECVERB     1              /* set to 1 for verbose DECCHECK  */
#define powers      DECPOWERS      /* old internal name  */

/* Local constants  */
#define DIVIDE      0x80           /* Divide operators  */
#define REMAINDER   0x40           /* ..  */
#define DIVIDEINT   0x20           /* ..  */
#define REMNEAR     0x10           /* ..  */
#define COMPARE     0x01           /* Compare operators  */
#define COMPMAX     0x02           /* ..  */
#define COMPMIN     0x03           /* ..  */
#define COMPTOTAL   0x04           /* ..  */
#define COMPNAN     0x05           /* .. [NaN processing]  */
#define COMPSIG     0x06           /* .. [signaling COMPARE]  */
#define COMPMAXMAG  0x07           /* ..  */
#define COMPMINMAG  0x08           /* ..  */

#define DEC_sNaN     0x40000000    /* local status: sNaN signal  */
#define BADINT  (Int)0x80000000    /* most-negative Int; error indicator  */
/* Next two indicate an integer >= 10**6, and its parity (bottom bit)  */
#define BIGEVEN (Int)0x80000002
#define BIGODD  (Int)0x80000003

static const Unit uarrone[1]={1};   /* Unit array of 1, used for incrementing  */

/* ------------------------------------------------------------------ */
/* round-for-reround digits                                           */
/* ------------------------------------------------------------------ */
#if 0
static const uByte DECSTICKYTAB[10]={1,1,2,3,4,6,6,7,8,9}; /* used if sticky */
#endif

/* ------------------------------------------------------------------ */
/* Powers of ten (powers[n]==10**n, 0<=n<=9)                          */
/* ------------------------------------------------------------------ */
static const uInt DECPOWERS[10]={1, 10, 100, 1000, 10000, 100000, 1000000,
                          10000000, 100000000, 1000000000};


/* Granularity-dependent code */
#if DECDPUN<=4
  #define eInt  Int           /* extended integer  */
  #define ueInt uInt          /* unsigned extended integer  */
  /* Constant multipliers for divide-by-power-of five using reciprocal  */
  /* multiply, after removing powers of 2 by shifting, and final shift  */
  /* of 17 [we only need up to **4]  */
  static const uInt multies[]={131073, 26215, 5243, 1049, 210};
  /* QUOT10 -- macro to return the quotient of unit u divided by 10**n  */
  #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17)
#else
  /* For DECDPUN>4 non-ANSI-89 64-bit types are needed.  */
  #if !DECUSE64
    #error decNumber.c: DECUSE64 must be 1 when DECDPUN>4
  #endif
  #define eInt  Long          /* extended integer  */
  #define ueInt uLong         /* unsigned extended integer  */
#endif

/* Local routines */
static decNumber * decAddOp(decNumber *, const decNumber *, const decNumber *,
                              decContext *, uByte, uInt *);
static Flag        decBiStr(const char *, const char *, const char *);
static uInt        decCheckMath(const decNumber *, decContext *, uInt *);
static void        decApplyRound(decNumber *, decContext *, Int, uInt *);
static Int         decCompare(const decNumber *lhs, const decNumber *rhs, Flag);
static decNumber * decCompareOp(decNumber *, const decNumber *,
                              const decNumber *, decContext *,
                              Flag, uInt *);
static void        decCopyFit(decNumber *, const decNumber *, decContext *,
                              Int *, uInt *);
static decNumber * decDecap(decNumber *, Int);
static decNumber * decDivideOp(decNumber *, const decNumber *,
                              const decNumber *, decContext *, Flag, uInt *);
static decNumber * decExpOp(decNumber *, const decNumber *,
                              decContext *, uInt *);
static void        decFinalize(decNumber *, decContext *, Int *, uInt *);
static Int         decGetDigits(Unit *, Int);
static Int         decGetInt(const decNumber *);
static decNumber * decLnOp(decNumber *, const decNumber *,
                              decContext *, uInt *);
static decNumber * decMultiplyOp(decNumber *, const decNumber *,
                              const decNumber *, decContext *,
                              uInt *);
static decNumber * decNaNs(decNumber *, const decNumber *,
                              const decNumber *, decContext *, uInt *);
static decNumber * decQuantizeOp(decNumber *, const decNumber *,
                              const decNumber *, decContext *, Flag,
                              uInt *);
static void        decReverse(Unit *, Unit *);
static void        decSetCoeff(decNumber *, decContext *, const Unit *,
                              IntInt *, uInt *);
static void        decSetMaxValue(decNumber *, decContext *);
static void        decSetOverflow(decNumber *, decContext *, uInt *);
static void        decSetSubnormal(decNumber *, decContext *, Int *, uInt *);
static Int         decShiftToLeast(Unit *, IntInt);
static Int         decShiftToMost(Unit *, IntInt);
static void        decStatus(decNumber *, uInt, decContext *);
static void        decToString(const decNumber *, char[], Flag);
static decNumber * decTrim(decNumber *, decContext *, Flag, Flag, Int *);
static Int         decUnitAddSub(const Unit *, Intconst Unit *, IntInt,
                              Unit *, Int);
static Int         decUnitCompare(const Unit *, Intconst Unit *, IntInt);

#if !DECSUBSET
/* decFinish == decFinalize when no subset arithmetic needed */
#define decFinish(a,b,c,d) decFinalize(a,b,c,d)
#else
static void        decFinish(decNumber *, decContext *, Int *, uInt *);
static decNumber * decRoundOperand(const decNumber *, decContext *, uInt *);
#endif

/* Local macros */
/* masked special-values bits  */
#define SPECIALARG  (rhs->bits & DECSPECIAL)
#define SPECIALARGS ((lhs->bits | rhs->bits) & DECSPECIAL)

/* For use in ICU */
#define malloc(a) uprv_malloc(a)
#define free(a) uprv_free(a)

/* Diagnostic macros, etc. */
#if DECALLOC
/* Handle malloc/free accounting.  If enabled, our accountable routines  */
/* are used; otherwise the code just goes straight to the system malloc  */
/* and free routines.  */
#define malloc(a) decMalloc(a)
#define free(a) decFree(a)
#define DECFENCE 0x5a              /* corruption detector  */
/* 'Our' malloc and free:  */
static void *decMalloc(size_t);
static void  decFree(void *);
uInt decAllocBytes=0;              /* count of bytes allocated  */
/* Note that DECALLOC code only checks for storage buffer overflow.  */
/* To check for memory leaks, the decAllocBytes variable must be  */
/* checked to be 0 at appropriate times (e.g., after the test  */
/* harness completes a set of tests).  This checking may be unreliable  */
/* if the testing is done in a multi-thread environment.  */
#endif

#if DECCHECK
/* Optional checking routines.  Enabling these means that decNumber  */
/* and decContext operands to operator routines are checked for  */
/* correctness.  This roughly doubles the execution time of the  */
/* fastest routines (and adds 600+ bytes), so should not normally be  */
/* used in 'production'.  */
/* decCheckInexact is used to check that inexact results have a full  */
/* complement of digits (where appropriate -- this is not the case  */
/* for Quantize, for example)  */
#define DECUNRESU ((decNumber *)(void *)0xffffffff)
#define DECUNUSED ((const decNumber *)(void *)0xffffffff)
#define DECUNCONT ((decContext *)(void *)(0xffffffff))
static Flag decCheckOperands(decNumber *, const decNumber *,
                             const decNumber *, decContext *);
static Flag decCheckNumber(const decNumber *);
static void decCheckInexact(const decNumber *, decContext *);
#endif

#if DECTRACE || DECCHECK
/* Optional trace/debugging routines (may or may not be used)  */
void decNumberShow(const decNumber *);  /* displays the components of a number  */
static void decDumpAr(charconst Unit *, Int);
#endif

/* ================================================================== */
/* Conversions                                                        */
/* ================================================================== */

/* ------------------------------------------------------------------ */
/* from-int32 -- conversion from Int or uInt                          */
/*                                                                    */
/*  dn is the decNumber to receive the integer                        */
/*  in or uin is the integer to be converted                          */
/*  returns dn                                                        */
/*                                                                    */
/* No error is possible.                                              */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromInt32(decNumber *dn, Int in) {
  uInt unsig;
  if (in>=0) unsig=in;
   else {                               /* negative (possibly BADINT)  */
    if (in==BADINT) unsig=(uInt)1073741824*2; /* special case  */
     else unsig=-in;                    /* invert  */
    }
  /* in is now positive  */
  uprv_decNumberFromUInt32(dn, unsig);
  if (in<0) dn->bits=DECNEG;            /* sign needed  */
  return dn;
  } /* decNumberFromInt32  */

U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromUInt32(decNumber *dn, uInt uin) {
  Unit *up;                             /* work pointer  */
  uprv_decNumberZero(dn);                    /* clean  */
  if (uin==0) return dn;                /* [or decGetDigits bad call]  */
  for (up=dn->lsu; uin>0; up++) {
    *up=(Unit)(uin%(DECDPUNMAX+1));
    uin=uin/(DECDPUNMAX+1);
    }
  dn->digits=decGetDigits(dn->lsu, static_cast<int32_t>(up - dn->lsu));
  return dn;
  } /* decNumberFromUInt32  */

/* ------------------------------------------------------------------ */
/* to-int32 -- conversion to Int or uInt                              */
/*                                                                    */
/*  dn is the decNumber to convert                                    */
/*  set is the context for reporting errors                           */
/*  returns the converted decNumber, or 0 if Invalid is set           */
/*                                                                    */
/* Invalid is set if the decNumber does not have exponent==0 or if    */
/* it is a NaN, Infinite, or out-of-range.                            */
/* ------------------------------------------------------------------ */
U_CAPI Int U_EXPORT2 uprv_decNumberToInt32(const decNumber *dn, decContext *set) {
  #if DECCHECK
  if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
  #endif

  /* special or too many digits, or bad exponent  */
  if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0) ; /* bad  */
   else { /* is a finite integer with 10 or fewer digits  */
    Int d;                         /* work  */
    const Unit *up;                /* ..  */
    uInt hi=0, lo;                 /* ..  */
    up=dn->lsu;                    /* -> lsu  */
    lo=*up;                        /* get 1 to 9 digits  */
    #if DECDPUN>1                  /* split to higher  */
      hi=lo/10;
      lo=lo%10;
    #endif
    up++;
    /* collect remaining Units, if any, into hi  */
    for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1];
    /* now low has the lsd, hi the remainder  */
    if (hi>214748364 || (hi==214748364 && lo>7)) { /* out of range?  */
      /* most-negative is a reprieve  */
      if (dn->bits&DECNEG && hi==214748364 && lo==8) return 0x80000000;
      /* bad -- drop through  */
      }
     else { /* in-range always  */
      Int i=X10(hi)+lo;
      if (dn->bits&DECNEG) return -i;
      return i;
      }
    } /* integer  */
  uprv_decContextSetStatus(set, DEC_Invalid_operation); /* [may not return]  */
  return 0;
  } /* decNumberToInt32  */

U_CAPI uInt U_EXPORT2 uprv_decNumberToUInt32(const decNumber *dn, decContext *set) {
  #if DECCHECK
  if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
  #endif
  /* special or too many digits, or bad exponent, or negative (<0)  */
  if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0
    || (dn->bits&DECNEG && !ISZERO(dn)));                   /* bad  */
   else { /* is a finite integer with 10 or fewer digits  */
    Int d;                         /* work  */
    const Unit *up;                /* ..  */
    uInt hi=0, lo;                 /* ..  */
    up=dn->lsu;                    /* -> lsu  */
    lo=*up;                        /* get 1 to 9 digits  */
    #if DECDPUN>1                  /* split to higher  */
      hi=lo/10;
      lo=lo%10;
    #endif
    up++;
    /* collect remaining Units, if any, into hi  */
    for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1];

    /* now low has the lsd, hi the remainder  */
    if (hi>429496729 || (hi==429496729 && lo>5)) ; /* no reprieve possible  */
     else return X10(hi)+lo;
    } /* integer  */
  uprv_decContextSetStatus(set, DEC_Invalid_operation); /* [may not return]  */
  return 0;
  } /* decNumberToUInt32  */

/* ------------------------------------------------------------------ */
/* to-scientific-string -- conversion to numeric string               */
/* to-engineering-string -- conversion to numeric string              */
/*                                                                    */
/*   decNumberToString(dn, string);                                   */
/*   decNumberToEngString(dn, string);                                */
/*                                                                    */
/*  dn is the decNumber to convert                                    */
/*  string is the string where the result will be laid out            */
/*                                                                    */
/*  string must be at least dn->digits+14 characters long             */
/*                                                                    */
/*  No error is possible, and no status can be set.                   */
/* ------------------------------------------------------------------ */
U_CAPI char * U_EXPORT2 uprv_decNumberToString(const decNumber *dn, char *string){
  decToString(dn, string, 0);
  return string;
  } /* DecNumberToString  */

U_CAPI char * U_EXPORT2 uprv_decNumberToEngString(const decNumber *dn, char *string){
  decToString(dn, string, 1);
  return string;
  } /* DecNumberToEngString  */

/* ------------------------------------------------------------------ */
/* to-number -- conversion from numeric string                        */
/*                                                                    */
/* decNumberFromString -- convert string to decNumber                 */
/*   dn        -- the number structure to fill                        */
/*   chars[]   -- the string to convert ('\0' terminated)             */
/*   set       -- the context used for processing any error,          */
/*                determining the maximum precision available         */
/*                (set.digits), determining the maximum and minimum   */
/*                exponent (set.emax and set.emin), determining if    */
/*                extended values are allowed, and checking the       */
/*                rounding mode if overflow occurs or rounding is     */
/*                needed.                                             */
/*                                                                    */
/* The length of the coefficient and the size of the exponent are     */
/* checked by this routine, so the correct error (Underflow or        */
/* Overflow) can be reported or rounding applied, as necessary.       */
/*                                                                    */
/* If bad syntax is detected, the result will be a quiet NaN.         */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromString(decNumber *dn, const char chars[],
                                decContext *set) {
  Int   exponent=0;                /* working exponent [assume 0]  */
  uByte bits=0;                    /* working flags [assume +ve]  */
  Unit  *res;                      /* where result will be built  */
  Unit  resbuff[SD2U(DECBUFFER+9)];/* local buffer in case need temporary  */
                                   /* [+9 allows for ln() constants]  */
  Unit  *allocres=nullptr;            /* -> allocated result, iff allocated  */
  Int   d=0;                       /* count of digits found in decimal part  */
  const char *dotchar=nullptr;        /* where dot was found  */
  const char *cfirst=chars;        /* -> first character of decimal part  */
  const char *last=nullptr;           /* -> last digit of decimal part  */
  const char *c;                   /* work  */
  Unit  *up;                       /* ..  */
  #if DECDPUN>1
  Int   cut, out;                  /* ..  */
  #endif
  Int   residue;                   /* rounding residue  */
  uInt  status=0;                  /* error code  */

  #if DECCHECK
  if (decCheckOperands(DECUNRESU, DECUNUSED, DECUNUSED, set))
    return uprv_decNumberZero(dn);
  #endif

  do {                             /* status & malloc protection  */
    for (c=chars;; c++) {          /* -> input character  */
      if (*c>='0' && *c<='9') {    /* test for Arabic digit  */
        last=c;
        d++;                       /* count of real digits  */
        continue;                  /* still in decimal part  */
        }
      if (*c=='.' && dotchar==nullptr) { /* first '.'  */
        dotchar=c;                 /* record offset into decimal part  */
        if (c==cfirst) cfirst++;   /* first digit must follow  */
        continue;}
      if (c==chars) {              /* first in string...  */
        if (*c=='-') {             /* valid - sign  */
          cfirst++;
          bits=DECNEG;
          continue;}
        if (*c=='+') {             /* valid + sign  */
          cfirst++;
          continue;}
        }
      /* *c is not a digit, or a valid +, -, or '.'  */
      break;
      } /* c  */

    if (last==nullptr) {              /* no digits yet  */
      status=DEC_Conversion_syntax;/* assume the worst  */
      if (*c=='\0'break;         /* and no more to come...  */
      #if DECSUBSET
      /* if subset then infinities and NaNs are not allowed  */
      if (!set->extended) break;   /* hopeless  */
      #endif
      /* Infinities and NaNs are possible, here  */
      if (dotchar!=nullptr) break;    /* .. unless had a dot  */
      uprv_decNumberZero(dn);           /* be optimistic  */
      if (decBiStr(c, "infinity""INFINITY")
       || decBiStr(c, "inf""INF")) {
        dn->bits=bits | DECINF;
        status=0;                  /* is OK  */
        break/* all done  */
        }
      /* a NaN expected  */
      /* 2003.09.10 NaNs are now permitted to have a sign  */
      dn->bits=bits | DECNAN;      /* assume simple NaN  */
      if (*c=='s' || *c=='S') {    /* looks like an sNaN  */
        c++;
        dn->bits=bits | DECSNAN;
        }
      if (*c!='n' && *c!='N'break;    /* check caseless "NaN"  */
      c++;
      if (*c!='a' && *c!='A'break;    /* ..  */
      c++;
      if (*c!='n' && *c!='N'break;    /* ..  */
      c++;
      /* now either nothing, or nnnn payload, expected  */
      /* -> start of integer and skip leading 0s [including plain 0]  */
      for (cfirst=c; *cfirst=='0';) cfirst++;
      if (*cfirst=='\0') {         /* "NaN" or "sNaN", maybe with all 0s  */
        status=0;                  /* it's good  */
        break;                     /* ..  */
        }
      /* something other than 0s; setup last and d as usual [no dots]  */
      for (c=cfirst;; c++, d++) {
        if (*c<'0' || *c>'9'break/* test for Arabic digit  */
        last=c;
        }
      if (*c!='\0'break;         /* not all digits  */
      if (d>set->digits-1) {
        /* [NB: payload in a decNumber can be full length unless  */
        /* clamped, in which case can only be digits-1]  */
        if (set->clamp) break;
        if (d>set->digits) break;
        } /* too many digits?  */
      /* good; drop through to convert the integer to coefficient  */
      status=0;                    /* syntax is OK  */
      bits=dn->bits;               /* for copy-back  */
      } /* last==nullptr  */

     else if (*c!='\0') {          /* more to process...  */
      /* had some digits; exponent is only valid sequence now  */
      Flag nege;                   /* 1=negative exponent  */
      const char *firstexp;        /* -> first significant exponent digit  */
      status=DEC_Conversion_syntax;/* assume the worst  */
      if (*c!='e' && *c!='E'break;
      /* Found 'e' or 'E' -- now process explicit exponent */
      /* 1998.07.11: sign no longer required  */
      nege=0;
      c++;                         /* to (possible) sign  */
      if (*c=='-') {nege=1; c++;}
       else if (*c=='+') c++;
      if (*c=='\0'break;

      for (; *c=='0' && *(c+1)!='\0';) c++;  /* strip insignificant zeros  */
      firstexp=c;                            /* save exponent digit place  */
      uInt uexponent = 0;   /* Avoid undefined behavior on signed int overflow */
      for (; ;c++) {
        if (*c<'0' || *c>'9'break;         /* not a digit  */
        uexponent=X10(uexponent)+(uInt)*c-(uInt)'0';
        } /* c  */
      exponent = (Int)uexponent;
      /* if not now on a '\0', *c must not be a digit  */
      if (*c!='\0'break;

      /* (this next test must be after the syntax checks)  */
      /* if it was too long the exponent may have wrapped, so check  */
      /* carefully and set it to a certain overflow if wrap possible  */
      if (c>=firstexp+9+1) {
        if (c>firstexp+9+1 || *firstexp>'1') exponent=DECNUMMAXE*2;
        /* [up to 1999999999 is OK, for example 1E-1000000998]  */
        }
      if (nege) exponent=-exponent;     /* was negative  */
      status=0;                         /* is OK  */
      } /* stuff after digits  */

    /* Here when whole string has been inspected; syntax is good  */
    /* cfirst->first digit (never dot), last->last digit (ditto)  */

    /* strip leading zeros/dot [leave final 0 if all 0's]  */
    if (*cfirst=='0') {                 /* [cfirst has stepped over .]  */
      for (c=cfirst; c<last; c++, cfirst++) {
        if (*c=='.'continue;          /* ignore dots  */
        if (*c!='0'break;             /* non-zero found  */
        d--;                            /* 0 stripped  */
        } /* c  */
      #if DECSUBSET
      /* make a rapid exit for easy zeros if !extended  */
      if (*cfirst=='0' && !set->extended) {
        uprv_decNumberZero(dn);              /* clean result  */
        break;                          /* [could be return]  */
        }
      #endif
      } /* at least one leading 0  */

    /* Handle decimal point...  */
    if (dotchar!=nullptr && dotchar<last)  /* non-trailing '.' found?  */
      exponent -= static_cast<int32_t>(last-dotchar);         /* adjust exponent  */
    /* [we can now ignore the .]  */

    /* OK, the digits string is good.  Assemble in the decNumber, or in  */
    /* a temporary units array if rounding is needed  */
    if (d<=set->digits) res=dn->lsu;    /* fits into supplied decNumber  */
     else {                             /* rounding needed  */
      Int needbytes=D2U(d)*sizeof(Unit);/* bytes needed  */
      res=resbuff;                      /* assume use local buffer  */
      if (needbytes>(Int)sizeof(resbuff)) { /* too big for local  */
        allocres=(Unit *)malloc(needbytes);
        if (allocres==nullptr) {status|=DEC_Insufficient_storage; break;}
        res=allocres;
        }
      }
    /* res now -> number lsu, buffer, or allocated storage for Unit array  */

    /* Place the coefficient into the selected Unit array  */
    /* [this is often 70% of the cost of this function when DECDPUN>1]  */
    #if DECDPUN>1
    out=0;                         /* accumulator  */
    up=res+D2U(d)-1;               /* -> msu  */
    cut=d-(up-res)*DECDPUN;        /* digits in top unit  */
    for (c=cfirst;; c++) {         /* along the digits  */
      if (*c=='.'continue;       /* ignore '.' [don't decrement cut]  */
      out=X10(out)+(Int)*c-(Int)'0';
      if (c==last) break;          /* done [never get to trailing '.']  */
      cut--;
      if (cut>0) continue;         /* more for this unit  */
      *up=(Unit)out;               /* write unit  */
      up--;                        /* prepare for unit below..  */
      cut=DECDPUN;                 /* ..  */
      out=0;                       /* ..  */
      } /* c  */
    *up=(Unit)out;                 /* write lsu  */

    #else
    /* DECDPUN==1  */
    up=res;                        /* -> lsu  */
    for (c=last; c>=cfirst; c--) { /* over each character, from least  */
      if (*c=='.'continue;       /* ignore . [don't step up]  */
      *up=(Unit)((Int)*c-(Int)'0');
      up++;
      } /* c  */
    #endif

    dn->bits=bits;
    dn->exponent=exponent;
    dn->digits=d;

    /* if not in number (too long) shorten into the number  */
    if (d>set->digits) {
      residue=0;
      decSetCoeff(dn, set, res, d, &residue, &status);
      /* always check for overflow or subnormal and round as needed  */
      decFinalize(dn, set, &residue, &status);
      }
     else { /* no rounding, but may still have overflow or subnormal  */
      /* [these tests are just for performance; finalize repeats them]  */
      if ((dn->exponent-1<set->emin-dn->digits)
       || (dn->exponent-1>set->emax-set->digits)) {
        residue=0;
        decFinalize(dn, set, &residue, &status);
        }
      }
    /* decNumberShow(dn);  */
    } while(0);                         /* [for break]  */

  if (allocres!=nullptr) free(allocres);   /* drop any storage used  */
  if (status!=0) decStatus(dn, status, set);
  return dn;
  } /* decNumberFromString */

/* ================================================================== */
/* Operators                                                          */
/* ================================================================== */

/* ------------------------------------------------------------------ */
/* decNumberAbs -- absolute value operator                            */
/*                                                                    */
/*   This computes C = abs(A)                                         */
/*                                                                    */
/*   res is C, the result.  C may be A                                */
/*   rhs is A                                                         */
/*   set is the context                                               */
/*                                                                    */
/* See also decNumberCopyAbs for a quiet bitwise version of this.     */
/* C must have space for set->digits digits.                          */
/* ------------------------------------------------------------------ */
/* This has the same effect as decNumberPlus unless A is negative,    */
/* in which case it has the same effect as decNumberMinus.            */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberAbs(decNumber *res, const decNumber *rhs,
                         decContext *set) {
  decNumber dzero;                      /* for 0  */
  uInt status=0;                        /* accumulator  */

  #if DECCHECK
  if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
  #endif

  uprv_decNumberZero(&dzero);                /* set 0  */
  dzero.exponent=rhs->exponent;         /* [no coefficient expansion]  */
  decAddOp(res, &dzero, rhs, set, (uByte)(rhs->bits & DECNEG), &status);
  if (status!=0) decStatus(res, status, set);
  #if DECCHECK
  decCheckInexact(res, set);
  #endif
  return res;
  } /* decNumberAbs  */

/* ------------------------------------------------------------------ */
/* decNumberAdd -- add two Numbers                                    */
/*                                                                    */
/*   This computes C = A + B                                          */
/*                                                                    */
/*   res is C, the result.  C may be A and/or B (e.g., X=X+X)         */
/*   lhs is A                                                         */
/*   rhs is B                                                         */
/*   set is the context                                               */
/*                                                                    */
/* C must have space for set->digits digits.                          */
/* ------------------------------------------------------------------ */
/* This just calls the routine shared with Subtract                   */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberAdd(decNumber *res, const decNumber *lhs,
                         const decNumber *rhs, decContext *set) {
  uInt status=0;                        /* accumulator  */
  decAddOp(res, lhs, rhs, set, 0, &status);
  if (status!=0) decStatus(res, status, set);
  #if DECCHECK
  decCheckInexact(res, set);
  #endif
  return res;
  } /* decNumberAdd  */

/* ------------------------------------------------------------------ */
/* decNumberAnd -- AND two Numbers, digitwise                         */
/*                                                                    */
/*   This computes C = A & B                                          */
/*                                                                    */
/*   res is C, the result.  C may be A and/or B (e.g., X=X&X)         */
/*   lhs is A                                                         */
/*   rhs is B                                                         */
/*   set is the context (used for result length and error report)     */
/*                                                                    */
/* C must have space for set->digits digits.                          */
/*                                                                    */
/* Logical function restrictions apply (see above); a NaN is          */
/* returned with Invalid_operation if a restriction is violated.      */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberAnd(decNumber *res, const decNumber *lhs,
                         const decNumber *rhs, decContext *set) {
  const Unit *ua, *ub;                  /* -> operands  */
  const Unit *msua, *msub;              /* -> operand msus  */
  Unit *uc,  *msuc;                     /* -> result and its msu  */
  Int   msudigs;                        /* digits in res msu  */
  #if DECCHECK
  if (decCheckOperands(res, lhs, rhs, set)) return res;
  #endif

  if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
   || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
    decStatus(res, DEC_Invalid_operation, set);
    return res;
    }

  /* operands are valid  */
  ua=lhs->lsu;                          /* bottom-up  */
  ub=rhs->lsu;                          /* ..  */
  uc=res->lsu;                          /* ..  */
  msua=ua+D2U(lhs->digits)-1;           /* -> msu of lhs  */
  msub=ub+D2U(rhs->digits)-1;           /* -> msu of rhs  */
  msuc=uc+D2U(set->digits)-1;           /* -> msu of result  */
  msudigs=MSUDIGITS(set->digits);       /* [faster than remainder]  */
  for (; uc<=msuc; ua++, ub++, uc++) {  /* Unit loop  */
    Unit a, b;                          /* extract units  */
    if (ua>msua) a=0;
     else a=*ua;
    if (ub>msub) b=0;
     else b=*ub;
    *uc=0;                              /* can now write back  */
    if (a|b) {                          /* maybe 1 bits to examine  */
      Int i, j;
      *uc=0;                            /* can now write back  */
      /* This loop could be unrolled and/or use BIN2BCD tables  */
      for (i=0; i<DECDPUN; i++) {
        if (a&b&1) *uc=*uc+(Unit)powers[i];  /* effect AND  */
        j=a%10;
        a=a/10;
        j|=b%10;
        b=b/10;
        if (j>1) {
          decStatus(res, DEC_Invalid_operation, set);
          return res;
          }
        if (uc==msuc && i==msudigs-1) break/* just did final digit  */
        } /* each digit  */
      } /* both OK  */
    } /* each unit  */
  /* [here uc-1 is the msu of the result]  */
  res->digits=decGetDigits(res->lsu, static_cast<int32_t>(uc - res->lsu));
  res->exponent=0;                      /* integer  */
  res->bits=0;                          /* sign=0  */
  return res;  /* [no status to set]  */
  } /* decNumberAnd  */

/* ------------------------------------------------------------------ */
/* decNumberCompare -- compare two Numbers                            */
/*                                                                    */
/*   This computes C = A ? B                                          */
/*                                                                    */
/*   res is C, the result.  C may be A and/or B (e.g., X=X?X)         */
/*   lhs is A                                                         */
/*   rhs is B                                                         */
/*   set is the context                                               */
/*                                                                    */
/* C must have space for one digit (or NaN).                          */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompare(decNumber *res, const decNumber *lhs,
                             const decNumber *rhs, decContext *set) {
  uInt status=0;                        /* accumulator  */
  decCompareOp(res, lhs, rhs, set, COMPARE, &status);
  if (status!=0) decStatus(res, status, set);
  return res;
  } /* decNumberCompare  */

/* ------------------------------------------------------------------ */
/* decNumberCompareSignal -- compare, signalling on all NaNs          */
/*                                                                    */
/*   This computes C = A ? B                                          */
/*                                                                    */
/*   res is C, the result.  C may be A and/or B (e.g., X=X?X)         */
/*   lhs is A                                                         */
/*   rhs is B                                                         */
/*   set is the context                                               */
/*                                                                    */
/* C must have space for one digit (or NaN).                          */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareSignal(decNumber *res, const decNumber *lhs,
                                   const decNumber *rhs, decContext *set) {
  uInt status=0;                        /* accumulator  */
  decCompareOp(res, lhs, rhs, set, COMPSIG, &status);
  if (status!=0) decStatus(res, status, set);
  return res;
  } /* decNumberCompareSignal  */

/* ------------------------------------------------------------------ */
/* decNumberCompareTotal -- compare two Numbers, using total ordering */
/*                                                                    */
/*   This computes C = A ? B, under total ordering                    */
/*                                                                    */
/*   res is C, the result.  C may be A and/or B (e.g., X=X?X)         */
/*   lhs is A                                                         */
/*   rhs is B                                                         */
/*   set is the context                                               */
/*                                                                    */
/* C must have space for one digit; the result will always be one of  */
/* -1, 0, or 1.                                                       */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotal(decNumber *res, const decNumber *lhs,
                                  const decNumber *rhs, decContext *set) {
  uInt status=0;                        /* accumulator  */
  decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
  if (status!=0) decStatus(res, status, set);
  return res;
  } /* decNumberCompareTotal  */

/* ------------------------------------------------------------------ */
/* decNumberCompareTotalMag -- compare, total ordering of magnitudes  */
/*                                                                    */
/*   This computes C = |A| ? |B|, under total ordering                */
/*                                                                    */
/*   res is C, the result.  C may be A and/or B (e.g., X=X?X)         */
/*   lhs is A                                                         */
/*   rhs is B                                                         */
/*   set is the context                                               */
/*                                                                    */
/* C must have space for one digit; the result will always be one of  */
/* -1, 0, or 1.                                                       */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotalMag(decNumber *res, const decNumber *lhs,
                                     const decNumber *rhs, decContext *set) {
  uInt status=0;                   /* accumulator  */
  uInt needbytes;                  /* for space calculations  */
  decNumber bufa[D2N(DECBUFFER+1)];/* +1 in case DECBUFFER=0  */
  decNumber *allocbufa=nullptr;       /* -> allocated bufa, iff allocated  */
  decNumber bufb[D2N(DECBUFFER+1)];
  decNumber *allocbufb=nullptr;       /* -> allocated bufb, iff allocated  */
  decNumber *a, *b;                /* temporary pointers  */

  #if DECCHECK
  if (decCheckOperands(res, lhs, rhs, set)) return res;
  #endif

  do {                                  /* protect allocated storage  */
    /* if either is negative, take a copy and absolute  */
    if (decNumberIsNegative(lhs)) {     /* lhs<0  */
      a=bufa;
      needbytes=sizeof(decNumber)+(D2U(lhs->digits)-1)*sizeof(Unit);
      if (needbytes>sizeof(bufa)) {     /* need malloc space  */
        allocbufa=(decNumber *)malloc(needbytes);
        if (allocbufa==nullptr) {          /* hopeless -- abandon  */
          status|=DEC_Insufficient_storage;
          break;}
        a=allocbufa;                    /* use the allocated space  */
        }
      uprv_decNumberCopy(a, lhs);            /* copy content  */
      a->bits&=~DECNEG;                 /* .. and clear the sign  */
      lhs=a;                            /* use copy from here on  */
      }
    if (decNumberIsNegative(rhs)) {     /* rhs<0  */
      b=bufb;
      needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
      if (needbytes>sizeof(bufb)) {     /* need malloc space  */
        allocbufb=(decNumber *)malloc(needbytes);
        if (allocbufb==nullptr) {          /* hopeless -- abandon  */
          status|=DEC_Insufficient_storage;
          break;}
        b=allocbufb;                    /* use the allocated space  */
        }
      uprv_decNumberCopy(b, rhs);            /* copy content  */
      b->bits&=~DECNEG;                 /* .. and clear the sign  */
      rhs=b;                            /* use copy from here on  */
      }
    decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
    } while(0);                         /* end protected  */

  if (allocbufa!=nullptr) free(allocbufa); /* drop any storage used  */
  if (allocbufb!=nullptr) free(allocbufb); /* ..  */
  if (status!=0) decStatus(res, status, set);
  return res;
  } /* decNumberCompareTotalMag  */

/* ------------------------------------------------------------------ */
/* decNumberDivide -- divide one number by another                    */
/*                                                                    */
/*   This computes C = A / B                                          */
/*                                                                    */
/*   res is C, the result.  C may be A and/or B (e.g., X=X/X)         */
/*   lhs is A                                                         */
/*   rhs is B                                                         */
/*   set is the context                                               */
/*                                                                    */
/* C must have space for set->digits digits.                          */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivide(decNumber *res, const decNumber *lhs,
                            const decNumber *rhs, decContext *set) {
  uInt status=0;                        /* accumulator  */
  decDivideOp(res, lhs, rhs, set, DIVIDE, &status);
  if (status!=0) decStatus(res, status, set);
  #if DECCHECK
  decCheckInexact(res, set);
  #endif
  return res;
  } /* decNumberDivide  */

/* ------------------------------------------------------------------ */
/* decNumberDivideInteger -- divide and return integer quotient       */
/*                                                                    */
/*   This computes C = A # B, where # is the integer divide operator  */
/*                                                                    */
/*   res is C, the result.  C may be A and/or B (e.g., X=X#X)         */
/*   lhs is A                                                         */
/*   rhs is B                                                         */
/*   set is the context                                               */
/*                                                                    */
/* C must have space for set->digits digits.                          */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivideInteger(decNumber *res, const decNumber *lhs,
                                   const decNumber *rhs, decContext *set) {
  uInt status=0;                        /* accumulator  */
  decDivideOp(res, lhs, rhs, set, DIVIDEINT, &status);
  if (status!=0) decStatus(res, status, set);
  return res;
  } /* decNumberDivideInteger  */

/* ------------------------------------------------------------------ */
/* decNumberExp -- exponentiation                                     */
/*                                                                    */
/*   This computes C = exp(A)                                         */
/*                                                                    */
/*   res is C, the result.  C may be A                                */
/*   rhs is A                                                         */
/*   set is the context; note that rounding mode has no effect        */
/*                                                                    */
/* C must have space for set->digits digits.                          */
/*                                                                    */
/* Mathematical function restrictions apply (see above); a NaN is     */
/* returned with Invalid_operation if a restriction is violated.      */
/*                                                                    */
/* Finite results will always be full precision and Inexact, except   */
/* when A is a zero or -Infinity (giving 1 or 0 respectively).        */
/*                                                                    */
/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will    */
/* almost always be correctly rounded, but may be up to 1 ulp in      */
/* error in rare cases.                                               */
/* ------------------------------------------------------------------ */
/* This is a wrapper for decExpOp which can handle the slightly wider */
/* (double) range needed by Ln (which has to be able to calculate     */
/* exp(-a) where a can be the tiniest number (Ntiny).                 */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberExp(decNumber *res, const decNumber *rhs,
                         decContext *set) {
  uInt status=0;                        /* accumulator  */
  #if DECSUBSET
  decNumber *allocrhs=nullptr;        /* non-nullptr if rounded rhs allocated  */
  #endif

  #if DECCHECK
  if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
  #endif

  /* Check restrictions; these restrictions ensure that if h=8 (see  */
  /* decExpOp) then the result will either overflow or underflow to 0.  */
  /* Other math functions restrict the input range, too, for inverses.  */
  /* If not violated then carry out the operation.  */
  if (!decCheckMath(rhs, set, &status)) do { /* protect allocation  */
    #if DECSUBSET
    if (!set->extended) {
      /* reduce operand and set lostDigits status, as needed  */
      if (rhs->digits>set->digits) {
        allocrhs=decRoundOperand(rhs, set, &status);
        if (allocrhs==nullptr) break;
        rhs=allocrhs;
        }
      }
    #endif
    decExpOp(res, rhs, set, &status);
    } while(0);                         /* end protected  */

  #if DECSUBSET
  if (allocrhs !=nullptr) free(allocrhs);  /* drop any storage used  */
  #endif
  /* apply significant status  */
  if (status!=0) decStatus(res, status, set);
  #if DECCHECK
  decCheckInexact(res, set);
  #endif
  return res;
  } /* decNumberExp  */

/* ------------------------------------------------------------------ */
/* decNumberFMA -- fused multiply add                                 */
/*                                                                    */
/*   This computes D = (A * B) + C with only one rounding             */
/*                                                                    */
/*   res is D, the result.  D may be A or B or C (e.g., X=FMA(X,X,X)) */
/*   lhs is A                                                         */
/*   rhs is B                                                         */
/*   fhs is C [far hand side]                                         */
/*   set is the context                                               */
/*                                                                    */
/* Mathematical function restrictions apply (see above); a NaN is     */
/* returned with Invalid_operation if a restriction is violated.      */
/*                                                                    */
/* C must have space for set->digits digits.                          */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberFMA(decNumber *res, const decNumber *lhs,
                         const decNumber *rhs, const decNumber *fhs,
                         decContext *set) {
  uInt status=0;                   /* accumulator  */
  decContext dcmul;                /* context for the multiplication  */
  uInt needbytes;                  /* for space calculations  */
  decNumber bufa[D2N(DECBUFFER*2+1)];
  decNumber *allocbufa=nullptr;       /* -> allocated bufa, iff allocated  */
  decNumber *acc;                  /* accumulator pointer  */
  decNumber dzero;                 /* work  */

  #if DECCHECK
  if (decCheckOperands(res, lhs, rhs, set)) return res;
  if (decCheckOperands(res, fhs, DECUNUSED, set)) return res;
  #endif

  do {                                  /* protect allocated storage  */
    #if DECSUBSET
    if (!set->extended) {               /* [undefined if subset]  */
      status|=DEC_Invalid_operation;
      break;}
    #endif
    /* Check math restrictions [these ensure no overflow or underflow]  */
    if ((!decNumberIsSpecial(lhs) && decCheckMath(lhs, set, &status))
     || (!decNumberIsSpecial(rhs) && decCheckMath(rhs, set, &status))
     || (!decNumberIsSpecial(fhs) && decCheckMath(fhs, set, &status))) break;
    /* set up context for multiply  */
    dcmul=*set;
    dcmul.digits=lhs->digits+rhs->digits; /* just enough  */
    /* [The above may be an over-estimate for subset arithmetic, but that's OK]  */
    dcmul.emax=DEC_MAX_EMAX;            /* effectively unbounded ..  */
    dcmul.emin=DEC_MIN_EMIN;            /* [thanks to Math restrictions]  */
    /* set up decNumber space to receive the result of the multiply  */
    acc=bufa;                           /* may fit  */
    needbytes=sizeof(decNumber)+(D2U(dcmul.digits)-1)*sizeof(Unit);
    if (needbytes>sizeof(bufa)) {       /* need malloc space  */
      allocbufa=(decNumber *)malloc(needbytes);
      if (allocbufa==nullptr) {            /* hopeless -- abandon  */
        status|=DEC_Insufficient_storage;
        break;}
      acc=allocbufa;                    /* use the allocated space  */
      }
    /* multiply with extended range and necessary precision  */
    /*printf("emin=%ld\n", dcmul.emin);  */
    decMultiplyOp(acc, lhs, rhs, &dcmul, &status);
    /* Only Invalid operation (from sNaN or Inf * 0) is possible in  */
    /* status; if either is seen than ignore fhs (in case it is  */
    /* another sNaN) and set acc to NaN unless we had an sNaN  */
    /* [decMultiplyOp leaves that to caller]  */
    /* Note sNaN has to go through addOp to shorten payload if  */
    /* necessary  */
    if ((status&DEC_Invalid_operation)!=0) {
      if (!(status&DEC_sNaN)) {         /* but be true invalid  */
        uprv_decNumberZero(res);             /* acc not yet set  */
        res->bits=DECNAN;
        break;
        }
      uprv_decNumberZero(&dzero);            /* make 0 (any non-NaN would do)  */
      fhs=&dzero;                       /* use that  */
      }
    #if DECCHECK
     else { /* multiply was OK  */
      if (status!=0) printf("Status=%08lx after FMA multiply\n", (LI)status);
      }
    #endif
    /* add the third operand and result -> res, and all is done  */
    decAddOp(res, acc, fhs, set, 0, &status);
    } while(0);                         /* end protected  */

  if (allocbufa!=nullptr) free(allocbufa); /* drop any storage used  */
  if (status!=0) decStatus(res, status, set);
  #if DECCHECK
  decCheckInexact(res, set);
  #endif
  return res;
  } /* decNumberFMA  */

/* ------------------------------------------------------------------ */
/* decNumberInvert -- invert a Number, digitwise                      */
/*                                                                    */
/*   This computes C = ~A                                             */
/*                                                                    */
/*   res is C, the result.  C may be A (e.g., X=~X)                   */
/*   rhs is A                                                         */
/*   set is the context (used for result length and error report)     */
/*                                                                    */
/* C must have space for set->digits digits.                          */
/*                                                                    */
/* Logical function restrictions apply (see above); a NaN is          */
/* returned with Invalid_operation if a restriction is violated.      */
/* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberInvert(decNumber *res, const decNumber *rhs,
                            decContext *set) {
  const Unit *ua, *msua;                /* -> operand and its msu  */
  Unit  *uc, *msuc;                     /* -> result and its msu  */
  Int   msudigs;                        /* digits in res msu  */
  #if DECCHECK
  if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
  #endif

  if (rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
    decStatus(res, DEC_Invalid_operation, set);
    return res;
    }
  /* operand is valid  */
  ua=rhs->lsu;                          /* bottom-up  */
  uc=res->lsu;                          /* ..  */
  msua=ua+D2U(rhs->digits)-1;           /* -> msu of rhs  */
  msuc=uc+D2U(set->digits)-1;           /* -> msu of result  */
  msudigs=MSUDIGITS(set->digits);       /* [faster than remainder]  */
  for (; uc<=msuc; ua++, uc++) {        /* Unit loop  */
    Unit a;                             /* extract unit  */
    Int  i, j;                          /* work  */
    if (ua>msua) a=0;
     else a=*ua;
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=38 H=90 G=68

¤ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.