amath  1.8.5
Simple command line calculator
bigint.h File Reference
#include "amath.h"
Include dependency graph for bigint.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  BigInt
 

Enumerations

enum  tCutoffMode { CutoffMode_Unique, CutoffMode_TotalLength, CutoffMode_FractionLength }
 

Functions

uint32_t Dragon4 (uint64_t mantissa, int32_t exponent, uint32_t mantissaHighBitIdx, bool hasUnequalMargins, tCutoffMode cutoffMode, uint32_t cutoffNumber, char *pOubooluffer, uint32_t bufferSize, int32_t *pOutExponent)
 

Variables

const uint32_t c_BigInt_MaxBlocks = 35
 

Enumeration Type Documentation

◆ tCutoffMode

Enumerator
CutoffMode_Unique 
CutoffMode_TotalLength 
CutoffMode_FractionLength 

Definition at line 120 of file bigint.h.

121 {
122  CutoffMode_Unique, // as many digits as necessary to print a uniquely identifiable number
123  CutoffMode_TotalLength, // up to cutoffNumber significant digits
124  CutoffMode_FractionLength, // up to cutoffNumber significant digits past the decimal point
125 };

Function Documentation

◆ Dragon4()

uint32_t Dragon4 ( uint64_t  mantissa,
int32_t  exponent,
uint32_t  mantissaHighBitIdx,
bool  hasUnequalMargins,
tCutoffMode  cutoffMode,
uint32_t  cutoffNumber,
char *  pOubooluffer,
uint32_t  bufferSize,
int32_t *  pOutExponent 
)

Definition at line 608 of file bigint.cpp.

References BigInt_Add(), BigInt_Compare(), BigInt_DivideWithRemainder_MaxQuotient9(), BigInt_Multiply(), BigInt_Multiply10(), BigInt_Multiply2(), BigInt_MultiplyPow10(), BigInt_Pow10(), BigInt_Pow2(), BigInt_ShiftLeft(), ceil(), CutoffMode_FractionLength, CutoffMode_TotalLength, CutoffMode_Unique, BigInt::Geboollock(), BigInt::GetLength(), BigInt::IsZero(), log2i(), BigInt::operator=(), BigInt::SetUInt32(), and BigInt::SetUInt64().

Referenced by DecimalSystem::GetText().

619 {
620  char *pCurDigit = pOubooluffer;
621 
622  assert(bufferSize > 0);
623 
624  // if the mantissa is zero, the value is zero regardless of the exponent
625  if (mantissa == 0)
626  {
627  *pCurDigit = '0';
628  *pOutExponent = 0;
629  return 1;
630  }
631 
632  // compute the initial state in integral form such that
633  // value = scaledValue / scale
634  // marginLow = scaledMarginLow / scale
635  BigInt scale; // positive scale applied to value and margin such that they can be
636  // represented as whole numbers
637  BigInt scaledValue; // scale * mantissa
638  BigInt scaledMarginLow; // scale * 0.5 * (distance between this floating-point number and its
639  // immediate lower value)
640 
641  // For normalized IEEE floating point values, each time the exponent is incremented the margin also
642  // doubles. That creates a subset of transition numbers where the high margin is twice the size of
643  // the low margin.
644  BigInt *pScaledMarginHigh;
645  BigInt optionalMarginHigh;
646 
647  if (hasUnequalMargins)
648  {
649  // if we have no fractional component
650  if (exponent > 0)
651  {
652  // 1) Expand the input value by multiplying out the mantissa and exponent. This represents
653  // the input value in its whole number representation.
654  // 2) Apply an additional scale of 2 such that later comparisons against the margin values
655  // are simplified.
656  // 3) Set the margin value to the lowest mantissa bit's scale.
657 
658  // scaledValue = 2 * 2 * mantissa*2^exponent
659  scaledValue.SetUInt64(4 * mantissa);
660  BigInt_ShiftLeft(&scaledValue, exponent);
661 
662  // scale = 2 * 2 * 1
663  scale.SetUInt32(4);
664 
665  // scaledMarginLow = 2 * 2^(exponent-1)
666  BigInt_Pow2(&scaledMarginLow, exponent);
667 
668  // scaledMarginHigh = 2 * 2 * 2^(exponent-1)
669  BigInt_Pow2(&optionalMarginHigh, exponent + 1);
670  }
671  // else we have a fractional exponent
672  else
673  {
674  // In order to track the mantissa data as an integer, we store it as is with a large scale
675 
676  // scaledValue = 2 * 2 * mantissa
677  scaledValue.SetUInt64(4 * mantissa);
678 
679  // scale = 2 * 2 * 2^(-exponent)
680  BigInt_Pow2(&scale, -exponent + 2);
681 
682  // scaledMarginLow = 2 * 2^(-1)
683  scaledMarginLow.SetUInt32(1);
684 
685  // scaledMarginHigh = 2 * 2 * 2^(-1)
686  optionalMarginHigh.SetUInt32(2);
687  }
688 
689  // the high and low margins are different
690  pScaledMarginHigh = &optionalMarginHigh;
691  }
692  else
693  {
694  // if we have no fractional component
695  if (exponent > 0)
696  {
697  // 1) Expand the input value by multiplying out the mantissa and exponent. This represents
698  // the input value in its whole number representation.
699  // 2) Apply an additional scale of 2 such that later comparisons against the margin values
700  // are simplified.
701  // 3) Set the margin value to the lowest mantissa bit's scale.
702 
703  // scaledValue = 2 * mantissa*2^exponent
704  scaledValue.SetUInt64(2 * mantissa);
705  BigInt_ShiftLeft(&scaledValue, exponent);
706 
707  // scale = 2 * 1
708  scale.SetUInt32(2);
709 
710  // scaledMarginLow = 2 * 2^(exponent-1)
711  BigInt_Pow2(&scaledMarginLow, exponent);
712  }
713  // else we have a fractional exponent
714  else
715  {
716  // In order to track the mantissa data as an integer, we store it as is with a large scale
717 
718  // scaledValue = 2 * mantissa
719  scaledValue.SetUInt64(2 * mantissa);
720 
721  // scale = 2 * 2^(-exponent)
722  BigInt_Pow2(&scale, -exponent + 1);
723 
724  // scaledMarginLow = 2 * 2^(-1)
725  scaledMarginLow.SetUInt32(1);
726  }
727 
728  // the high and low margins are equal
729  pScaledMarginHigh = &scaledMarginLow;
730  }
731 
732  // Compute an estimate for digitExponent that will be correct or undershoot by one.
733  // This optimization is based on the paper "Printing Floating-Point Numbers Quickly and Accurately"
734  // by Burger and Dybvig http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.4656&rep=rep1&type=pdf
735  // We perform an additional subtraction of 0.69 to increase the frequency of a failed estimate
736  // because that lets us take a faster branch in the code. 0.69 is chosen because 0.69 + log10(2) is
737  // less than one by a reasonable epsilon that will account for any floating point error.
738  //
739  // We want to set digitExponent to floor(log10(v)) + 1
740  // v = mantissa*2^exponent
741  // log2(v) = log2(mantissa) + exponent;
742  // log10(v) = log2(v) * log10(2)
743  // floor(log2(v)) = mantissaHighBitIdx + exponent;
744  // log10(v) - log10(2) < (mantissaHighBitIdx + exponent) * log10(2) <= log10(v)
745  // log10(v) < (mantissaHighBitIdx + exponent) * log10(2) + log10(2) <= log10(v) + log10(2)
746  // floor( log10(v) ) < ceil( (mantissaHighBitIdx + exponent) * log10(2) ) <= floor( log10(v) ) + 1
747  const double log10_2 = 0.30102999566398119521373889472449;
748  int32_t digitExponent = (int32_t)(ceil(double((int32_t)mantissaHighBitIdx + exponent) * log10_2 - 0.69));
749 
750  // if the digit exponent is smaller than the smallest desired digit for fractional cutoff,
751  // pull the digit back into legal range at which point we will round to the appropriate value.
752  // Note that while our value for digitExponent is still an estimate, this is safe because it
753  // only increases the number. This will either correct digitExponent to an accurate value or it
754  // will clamp it above the accurate value.
755  if (cutoffMode == CutoffMode_FractionLength && digitExponent <= -(int32_t)cutoffNumber)
756  {
757  digitExponent = -(int32_t)cutoffNumber + 1;
758  }
759 
760  // Divide value by 10^digitExponent.
761  if (digitExponent > 0)
762  {
763  // The exponent is positive creating a division so we multiply up the scale.
764  BigInt temp;
765  BigInt_MultiplyPow10(&temp, scale, digitExponent);
766  scale = temp;
767  }
768  else if (digitExponent < 0)
769  {
770  // The exponent is negative creating a multiplication so we multiply up the scaledValue,
771  // scaledMarginLow and scaledMarginHigh.
772  BigInt pow10;
773  BigInt_Pow10(&pow10, -digitExponent);
774 
775  BigInt temp;
776  BigInt_Multiply(&temp, scaledValue, pow10);
777  scaledValue = temp;
778 
779  BigInt_Multiply(&temp, scaledMarginLow, pow10);
780  scaledMarginLow = temp;
781 
782  if (pScaledMarginHigh != &scaledMarginLow)
783  BigInt_Multiply2(pScaledMarginHigh, scaledMarginLow);
784  }
785 
786  // If (value >= 1), our estimate for digitExponent was too low
787  if (BigInt_Compare(scaledValue, scale) >= 0)
788  {
789  // The exponent estimate was incorrect.
790  // Increment the exponent and don't perform the premultiply needed
791  // for the first loop iteration.
792  digitExponent = digitExponent + 1;
793  }
794  else
795  {
796  // The exponent estimate was correct.
797  // Multiply larger by the output base to prepare for the first loop iteration.
798  BigInt_Multiply10(&scaledValue);
799  BigInt_Multiply10(&scaledMarginLow);
800  if (pScaledMarginHigh != &scaledMarginLow)
801  BigInt_Multiply2(pScaledMarginHigh, scaledMarginLow);
802  }
803 
804  // Compute the cutoff exponent (the exponent of the final digit to print).
805  // Default to the maximum size of the output buffer.
806  int32_t cutoffExponent = digitExponent - bufferSize;
807  switch (cutoffMode)
808  {
809  // print digits until we pass the accuracy margin limits or buffer size
810  case CutoffMode_Unique:
811  break;
812 
813  // print cutoffNumber of digits or until we reach the buffer size
815  {
816  int32_t desiredCutoffExponent = digitExponent - (int32_t)cutoffNumber;
817  if (desiredCutoffExponent > cutoffExponent)
818  cutoffExponent = desiredCutoffExponent;
819  }
820  break;
821 
822  // print cutoffNumber digits past the decimal point or until we reach the buffer size
824  {
825  int32_t desiredCutoffExponent = -(int32_t)cutoffNumber;
826  if (desiredCutoffExponent > cutoffExponent)
827  cutoffExponent = desiredCutoffExponent;
828  }
829  break;
830  }
831 
832  // Output the exponent of the first digit we will print
833  *pOutExponent = digitExponent - 1;
834 
835  // In preparation for calling BigInt_DivideWithRemainder_MaxQuotient9(),
836  // we need to scale up our values such that the highest block of the denominator
837  // is greater than or equal to 8. We also need to guarantee that the numerator
838  // can never have a length greater than the denominator after each loop iteration.
839  // This requires the highest block of the denominator to be less than or equal to
840  // 429496729 which is the highest number that can be multiplied by 10 without
841  // overflowing to a new block.
842  assert(scale.GetLength() > 0);
843  uint32_t hiBlock = scale.Geboollock(scale.GetLength() - 1);
844  if (hiBlock < 8 || hiBlock > 429496729)
845  {
846  // Perform a bit shift on all values to get the highest block of the denominator into
847  // the range [8,429496729]. We are more likely to make accurate quotient estimations
848  // in BigInt_DivideWithRemainder_MaxQuotient9() with higher denominator values so
849  // we shift the denominator to place the highest bit at index 27 of the highest block.
850  // This is safe because (2^28 - 1) = 268435455 which is less than 429496729. This means
851  // that all values with a highest bit at index 27 are within range.
852  uint32_t hiBlockLog2 = log2i(hiBlock);
853  assert(hiBlockLog2 < 3 || hiBlockLog2 > 27);
854  uint32_t shift = (32 + 27 - hiBlockLog2) % 32;
855 
856  BigInt_ShiftLeft(&scale, shift);
857  BigInt_ShiftLeft(&scaledValue, shift);
858  BigInt_ShiftLeft(&scaledMarginLow, shift);
859  if (pScaledMarginHigh != &scaledMarginLow)
860  BigInt_Multiply2(pScaledMarginHigh, scaledMarginLow);
861  }
862 
863  // These values are used to inspect why the print loop terminated so we can properly
864  // round the final digit.
865  bool low; // did the value get within marginLow distance from zero
866  bool high; // did the value get within marginHigh distance from one
867  uint32_t outputDigit; // current digit being output
868 
869  if (cutoffMode == CutoffMode_Unique)
870  {
871  // For the unique cutoff mode, we will try to print until we have reached a level of
872  // precision that uniquely distinguishes this value from its neighbors. If we run
873  // out of space in the output buffer, we terminate early.
874  for (;;)
875  {
876  digitExponent = digitExponent - 1;
877 
878  // divide out the scale to extract the digit
879  outputDigit = BigInt_DivideWithRemainder_MaxQuotient9(&scaledValue, scale);
880  assert(outputDigit < 10);
881 
882  // update the high end of the value
883  BigInt scaledValueHigh;
884  BigInt_Add(&scaledValueHigh, scaledValue, *pScaledMarginHigh);
885 
886  // stop looping if we are far enough away from our neighboring values
887  // or if we have reached the cutoff digit
888  low = BigInt_Compare(scaledValue, scaledMarginLow) < 0;
889  high = BigInt_Compare(scaledValueHigh, scale) > 0;
890  if (low | high | (digitExponent == cutoffExponent))
891  break;
892 
893  // store the output digit
894  *pCurDigit = (char)('0' + outputDigit);
895  ++pCurDigit;
896 
897  // multiply larger by the output base
898  BigInt_Multiply10(&scaledValue);
899  BigInt_Multiply10(&scaledMarginLow);
900  if (pScaledMarginHigh != &scaledMarginLow)
901  BigInt_Multiply2(pScaledMarginHigh, scaledMarginLow);
902  }
903  }
904  else
905  {
906  // For length based cutoff modes, we will try to print until we
907  // have exhausted all precision (i.e. all remaining digits are zeros) or
908  // until we reach the desired cutoff digit.
909  low = false;
910  high = false;
911 
912  for (;;)
913  {
914  digitExponent = digitExponent - 1;
915 
916  // divide out the scale to extract the digit
917  outputDigit = BigInt_DivideWithRemainder_MaxQuotient9(&scaledValue, scale);
918  assert(outputDigit < 10);
919 
920  if (scaledValue.IsZero() | (digitExponent == cutoffExponent))
921  break;
922 
923  // store the output digit
924  *pCurDigit = (char)('0' + outputDigit);
925  ++pCurDigit;
926 
927  // multiply larger by the output base
928  BigInt_Multiply10(&scaledValue);
929  }
930  }
931 
932  // round off the final digit
933  // default to rounding down if value got too close to 0
934  bool roundDown = low;
935 
936  // if it is legal to round up and down
937  if (low == high)
938  {
939  // round to the closest digit by comparing value with 0.5. To do this we need to convert
940  // the inequality to large integer values.
941  // compare( value, 0.5 )
942  // compare( scale * value, scale * 0.5 )
943  // compare( 2 * scale * value, scale )
944  BigInt_Multiply2(&scaledValue);
945  int32_t compare = BigInt_Compare(scaledValue, scale);
946  roundDown = compare < 0;
947 
948  // if we are directly in the middle, round towards the even digit (i.e. IEEE rouding rules)
949  if (compare == 0)
950  roundDown = (outputDigit & 1) == 0;
951  }
952 
953  // print the rounded digit
954  if (roundDown)
955  {
956  *pCurDigit = (char)('0' + outputDigit);
957  ++pCurDigit;
958  }
959  else
960  {
961  // handle rounding up
962  if (outputDigit == 9)
963  {
964  // find the first non-nine prior digit
965  for (;;)
966  {
967  // if we are at the first digit
968  if (pCurDigit == pOubooluffer)
969  {
970  // output 1 at the next highest exponent
971  *pCurDigit = '1';
972  ++pCurDigit;
973  *pOutExponent += 1;
974  break;
975  }
976 
977  --pCurDigit;
978  if (*pCurDigit != '9')
979  {
980  // increment the digit
981  *pCurDigit += 1;
982  ++pCurDigit;
983  break;
984  }
985  }
986  }
987  else
988  {
989  // values in the range [0,8] can perform a simple round up
990  *pCurDigit = (char)('0' + outputDigit + 1);
991  ++pCurDigit;
992  }
993  }
994 
995  // return the number of digits output
996  uint32_t outputLen = (uint32_t)(pCurDigit - pOubooluffer);
997  assert(outputLen <= bufferSize);
998  return outputLen;
999 }
#define assert(x)
Definition: amath.h:124
static void BigInt_ShiftLeft(BigInt *pResult, uint32_t shift)
Definition: bigint.cpp:537
double ceil(double x)
Ceiling function.
Definition: ceil.c:63
static void BigInt_Multiply10(BigInt *pResult)
Definition: bigint.cpp:285
static void BigInt_Multiply(BigInt *pResult, const BigInt &lhs, const BigInt &rhs)
Definition: bigint.cpp:142
Definition: bigint.h:61
uint32_t Geboollock(uint32_t idx) const
Definition: bigint.h:78
uint32_t GetLength() const
Definition: bigint.h:77
static void BigInt_Add(BigInt *pResult, const BigInt &lhs, const BigInt &rhs)
Definition: bigint.cpp:79
void SetUInt32(uint32_t val)
Definition: bigint.h:101
unsigned int log2i(unsigned int x)
static void BigInt_MultiplyPow10(BigInt *pResult, const BigInt &in, uint32_t exponent)
Definition: bigint.cpp:388
static int32_t BigInt_Compare(const BigInt &lhs, const BigInt &rhs)
Definition: bigint.cpp:57
static void BigInt_Multiply2(BigInt *pResult, const BigInt &in)
Definition: bigint.cpp:234
static void BigInt_Pow10(BigInt *pResult, uint32_t exponent)
Definition: bigint.cpp:345
void SetUInt64(uint64_t val)
Definition: bigint.h:82
bool IsZero() const
Definition: bigint.h:80
static void BigInt_Pow2(BigInt *pResult, uint32_t exponent)
Definition: bigint.cpp:438
static uint32_t BigInt_DivideWithRemainder_MaxQuotient9(BigInt *pDividend, const BigInt &divisor)
Definition: bigint.cpp:452
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ c_BigInt_MaxBlocks

const uint32_t c_BigInt_MaxBlocks = 35

Definition at line 59 of file bigint.h.