mirror of
https://gitlab.com/rnger/amath
synced 2025-10-06 02:49:59 +00:00
483 lines
20 KiB
Groff
483 lines
20 KiB
Groff
.TH "lib/dconv/dragon4.h" 3 "Tue Jan 24 2017" "Version 1.6.2" "amath" \" -*- nroff -*-
|
|
.ad l
|
|
.nh
|
|
.SH NAME
|
|
lib/dconv/dragon4.h \- Convert floating point format to a decimal number in string format\&.
|
|
|
|
.SH SYNOPSIS
|
|
.br
|
|
.PP
|
|
\fC#include 'dstandard\&.h'\fP
|
|
.br
|
|
|
|
.SS "Enumerations"
|
|
|
|
.in +1c
|
|
.ti -1c
|
|
.RI "enum \fBtCutoffMode\fP { \fBCutoffMode_Unique\fP, \fBCutoffMode_TotalLength\fP, \fBCutoffMode_FractionLength\fP }"
|
|
.br
|
|
.in -1c
|
|
.SS "Functions"
|
|
|
|
.in +1c
|
|
.ti -1c
|
|
.RI "\fBtU32\fP \fBDragon4\fP (\fBtU64\fP mantissa, \fBtS32\fP exponent, \fBtU32\fP mantissaHighBitIdx, \fBtB\fP hasUnequalMargins, enum \fBtCutoffMode\fP cutoffMode, \fBtU32\fP cutoffNumber, \fBtC8\fP *pOutBuffer, \fBtU32\fP bufferSize, \fBtS32\fP *pOutExponent)"
|
|
.br
|
|
.RI "\fIDragon4 main\&. \fP"
|
|
.in -1c
|
|
.SH "Detailed Description"
|
|
.PP
|
|
Convert floating point format to a decimal number in string format\&.
|
|
|
|
This is an implementation the Dragon4 algorithm to convert a binary number in floating point format to a decimal number in string format\&. The function returns the number of digits written to the output buffer and the output is not NUL terminated\&.
|
|
.PP
|
|
Downloaded from:
|
|
.br
|
|
http://www.ryanjuckett.com/
|
|
.PP
|
|
Definition in file \fBdragon4\&.h\fP\&.
|
|
.SH "Enumeration Type Documentation"
|
|
.PP
|
|
.SS "enum \fBtCutoffMode\fP"
|
|
|
|
.PP
|
|
\fBEnumerator\fP
|
|
.in +1c
|
|
.TP
|
|
\fB\fICutoffMode_Unique \fP\fP
|
|
.TP
|
|
\fB\fICutoffMode_TotalLength \fP\fP
|
|
.TP
|
|
\fB\fICutoffMode_FractionLength \fP\fP
|
|
.PP
|
|
Definition at line 75 of file dragon4\&.h\&.
|
|
.PP
|
|
.nf
|
|
76 {
|
|
77 CutoffMode_Unique, // as many digits as necessary to print a uniquely identifiable number
|
|
78 CutoffMode_TotalLength, // up to cutoffNumber significant digits
|
|
79 CutoffMode_FractionLength, // up to cutoffNumber significant digits past the decimal point
|
|
80 };
|
|
.fi
|
|
.SH "Function Documentation"
|
|
.PP
|
|
.SS "\fBtU32\fP Dragon4 (\fBtU64\fP mantissa, \fBtS32\fP exponent, \fBtU32\fP mantissaHighBitIdx, \fBtB\fP hasUnequalMargins, enum \fBtCutoffMode\fP cutoffMode, \fBtU32\fP cutoffNumber, \fBtC8\fP * pOutBuffer, \fBtU32\fP bufferSize, \fBtS32\fP * pOutExponent)"
|
|
|
|
.PP
|
|
Dragon4 main\&. Downloaded from:
|
|
.br
|
|
http://www.ryanjuckett.com/
|
|
.PP
|
|
This is an implementation the Dragon4 algorithm to convert a binary number in floating point format to a decimal number in string format\&. The function returns the number of digits written to the output buffer and the output is not NUL terminated\&.
|
|
.PP
|
|
The floating point input value is (mantissa * 2^exponent)\&.
|
|
.PP
|
|
See the following papers for more information on the algorithm:
|
|
.br
|
|
'How to Print Floating-Point Numbers Accurately'
|
|
.br
|
|
Steele and White
|
|
.br
|
|
http://kurtstephens.com/files/p372-steele.pdf
|
|
.br
|
|
'Printing Floating-Point Numbers Quickly and Accurately'
|
|
.br
|
|
Burger and Dybvig
|
|
.br
|
|
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.4656&rep=rep1&type=pdf
|
|
.br
|
|
|
|
.PP
|
|
Definition at line 770 of file dragon4\&.cpp\&.
|
|
.PP
|
|
References BigInt_Add(), BigInt_Compare(), BigInt_DivideWithRemainder_MaxQuotient9(), BigInt_Multiply(), BigInt_Multiply10(), BigInt_Multiply2(), BigInt_MultiplyPow10(), BigInt_Pow10(), BigInt_Pow2(), BigInt_ShiftLeft(), CutoffMode_FractionLength, CutoffMode_TotalLength, CutoffMode_Unique, tBigInt::GetBlock(), tBigInt::GetLength(), tBigInt::IsZero(), LogBase2(), tBigInt::operator=(), tBigInt::SetU32(), and tBigInt::SetU64()\&.
|
|
.PP
|
|
Referenced by FormatPositional(), and FormatScientific()\&.
|
|
.PP
|
|
.nf
|
|
781 {
|
|
782 tC8 * pCurDigit = pOutBuffer;
|
|
783
|
|
784 RJ_ASSERT( bufferSize > 0 );
|
|
785
|
|
786 // if the mantissa is zero, the value is zero regardless of the exponent
|
|
787 if (mantissa == 0)
|
|
788 {
|
|
789 *pCurDigit = '0';
|
|
790 *pOutExponent = 0;
|
|
791 return 1;
|
|
792 }
|
|
793
|
|
794 // compute the initial state in integral form such that
|
|
795 // value = scaledValue / scale
|
|
796 // marginLow = scaledMarginLow / scale
|
|
797 tBigInt scale; // positive scale applied to value and margin such that they can be
|
|
798 // represented as whole numbers
|
|
799 tBigInt scaledValue; // scale * mantissa
|
|
800 tBigInt scaledMarginLow; // scale * 0\&.5 * (distance between this floating-point number and its
|
|
801 // immediate lower value)
|
|
802
|
|
803 // For normalized IEEE floating point values, each time the exponent is incremented the margin also
|
|
804 // doubles\&. That creates a subset of transition numbers where the high margin is twice the size of
|
|
805 // the low margin\&.
|
|
806 tBigInt * pScaledMarginHigh;
|
|
807 tBigInt optionalMarginHigh;
|
|
808
|
|
809 if ( hasUnequalMargins )
|
|
810 {
|
|
811 // if we have no fractional component
|
|
812 if (exponent > 0)
|
|
813 {
|
|
814 // 1) Expand the input value by multiplying out the mantissa and exponent\&. This represents
|
|
815 // the input value in its whole number representation\&.
|
|
816 // 2) Apply an additional scale of 2 such that later comparisons against the margin values
|
|
817 // are simplified\&.
|
|
818 // 3) Set the margin value to the lowest mantissa bit's scale\&.
|
|
819
|
|
820 // scaledValue = 2 * 2 * mantissa*2^exponent
|
|
821 scaledValue\&.SetU64( 4 * mantissa );
|
|
822 BigInt_ShiftLeft( &scaledValue, exponent );
|
|
823
|
|
824 // scale = 2 * 2 * 1
|
|
825 scale\&.SetU32( 4 );
|
|
826
|
|
827 // scaledMarginLow = 2 * 2^(exponent-1)
|
|
828 BigInt_Pow2( &scaledMarginLow, exponent );
|
|
829
|
|
830 // scaledMarginHigh = 2 * 2 * 2^(exponent-1)
|
|
831 BigInt_Pow2( &optionalMarginHigh, exponent + 1 );
|
|
832 }
|
|
833 // else we have a fractional exponent
|
|
834 else
|
|
835 {
|
|
836 // In order to track the mantissa data as an integer, we store it as is with a large scale
|
|
837
|
|
838 // scaledValue = 2 * 2 * mantissa
|
|
839 scaledValue\&.SetU64( 4 * mantissa );
|
|
840
|
|
841 // scale = 2 * 2 * 2^(-exponent)
|
|
842 BigInt_Pow2(&scale, -exponent + 2 );
|
|
843
|
|
844 // scaledMarginLow = 2 * 2^(-1)
|
|
845 scaledMarginLow\&.SetU32( 1 );
|
|
846
|
|
847 // scaledMarginHigh = 2 * 2 * 2^(-1)
|
|
848 optionalMarginHigh\&.SetU32( 2 );
|
|
849 }
|
|
850
|
|
851 // the high and low margins are different
|
|
852 pScaledMarginHigh = &optionalMarginHigh;
|
|
853 }
|
|
854 else
|
|
855 {
|
|
856 // if we have no fractional component
|
|
857 if (exponent > 0)
|
|
858 {
|
|
859 // 1) Expand the input value by multiplying out the mantissa and exponent\&. This represents
|
|
860 // the input value in its whole number representation\&.
|
|
861 // 2) Apply an additional scale of 2 such that later comparisons against the margin values
|
|
862 // are simplified\&.
|
|
863 // 3) Set the margin value to the lowest mantissa bit's scale\&.
|
|
864
|
|
865 // scaledValue = 2 * mantissa*2^exponent
|
|
866 scaledValue\&.SetU64( 2 * mantissa );
|
|
867 BigInt_ShiftLeft( &scaledValue, exponent );
|
|
868
|
|
869 // scale = 2 * 1
|
|
870 scale\&.SetU32( 2 );
|
|
871
|
|
872 // scaledMarginLow = 2 * 2^(exponent-1)
|
|
873 BigInt_Pow2( &scaledMarginLow, exponent );
|
|
874 }
|
|
875 // else we have a fractional exponent
|
|
876 else
|
|
877 {
|
|
878 // In order to track the mantissa data as an integer, we store it as is with a large scale
|
|
879
|
|
880 // scaledValue = 2 * mantissa
|
|
881 scaledValue\&.SetU64( 2 * mantissa );
|
|
882
|
|
883 // scale = 2 * 2^(-exponent)
|
|
884 BigInt_Pow2(&scale, -exponent + 1 );
|
|
885
|
|
886 // scaledMarginLow = 2 * 2^(-1)
|
|
887 scaledMarginLow\&.SetU32( 1 );
|
|
888 }
|
|
889
|
|
890 // the high and low margins are equal
|
|
891 pScaledMarginHigh = &scaledMarginLow;
|
|
892 }
|
|
893
|
|
894 // Compute an estimate for digitExponent that will be correct or undershoot by one\&.
|
|
895 // This optimization is based on the paper "Printing Floating-Point Numbers Quickly and Accurately"
|
|
896 // by Burger and Dybvig http://citeseerx\&.ist\&.psu\&.edu/viewdoc/download?doi=10\&.1\&.1\&.72\&.4656&rep=rep1&type=pdf
|
|
897 // We perform an additional subtraction of 0\&.69 to increase the frequency of a failed estimate
|
|
898 // because that lets us take a faster branch in the code\&. 0\&.69 is chosen because 0\&.69 + log10(2) is
|
|
899 // less than one by a reasonable epsilon that will account for any floating point error\&.
|
|
900 //
|
|
901 // We want to set digitExponent to floor(log10(v)) + 1
|
|
902 // v = mantissa*2^exponent
|
|
903 // log2(v) = log2(mantissa) + exponent;
|
|
904 // log10(v) = log2(v) * log10(2)
|
|
905 // floor(log2(v)) = mantissaHighBitIdx + exponent;
|
|
906 // log10(v) - log10(2) < (mantissaHighBitIdx + exponent) * log10(2) <= log10(v)
|
|
907 // log10(v) < (mantissaHighBitIdx + exponent) * log10(2) + log10(2) <= log10(v) + log10(2)
|
|
908 // floor( log10(v) ) < ceil( (mantissaHighBitIdx + exponent) * log10(2) ) <= floor( log10(v) ) + 1
|
|
909 const tF64 log10_2 = 0\&.30102999566398119521373889472449;
|
|
910 tS32 digitExponent = (tS32)(ceil(tF64((tS32)mantissaHighBitIdx + exponent) * log10_2 - 0\&.69));
|
|
911
|
|
912 // if the digit exponent is smaller than the smallest desired digit for fractional cutoff,
|
|
913 // pull the digit back into legal range at which point we will round to the appropriate value\&.
|
|
914 // Note that while our value for digitExponent is still an estimate, this is safe because it
|
|
915 // only increases the number\&. This will either correct digitExponent to an accurate value or it
|
|
916 // will clamp it above the accurate value\&.
|
|
917 if (cutoffMode == CutoffMode_FractionLength && digitExponent <= -(tS32)cutoffNumber)
|
|
918 {
|
|
919 digitExponent = -(tS32)cutoffNumber + 1;
|
|
920 }
|
|
921
|
|
922 // Divide value by 10^digitExponent\&.
|
|
923 if (digitExponent > 0)
|
|
924 {
|
|
925 // The exponent is positive creating a division so we multiply up the scale\&.
|
|
926 tBigInt temp;
|
|
927 BigInt_MultiplyPow10( &temp, scale, digitExponent );
|
|
928 scale = temp;
|
|
929 }
|
|
930 else if (digitExponent < 0)
|
|
931 {
|
|
932 // The exponent is negative creating a multiplication so we multiply up the scaledValue,
|
|
933 // scaledMarginLow and scaledMarginHigh\&.
|
|
934 tBigInt pow10;
|
|
935 BigInt_Pow10( &pow10, -digitExponent);
|
|
936
|
|
937 tBigInt temp;
|
|
938 BigInt_Multiply( &temp, scaledValue, pow10);
|
|
939 scaledValue = temp;
|
|
940
|
|
941 BigInt_Multiply( &temp, scaledMarginLow, pow10);
|
|
942 scaledMarginLow = temp;
|
|
943
|
|
944 if (pScaledMarginHigh != &scaledMarginLow)
|
|
945 BigInt_Multiply2( pScaledMarginHigh, scaledMarginLow );
|
|
946 }
|
|
947
|
|
948 // If (value + marginHigh) >= 1, our estimate for digitExponent was too low
|
|
949 tBigInt scaledValueHigh;
|
|
950 BigInt_Add( &scaledValueHigh, scaledValue, *pScaledMarginHigh );
|
|
951 if( BigInt_Compare(scaledValueHigh,scale) >= 0 )
|
|
952 {
|
|
953 // The exponent estimate was incorrect\&.
|
|
954 // Increment the exponent and don't perform the premultiply needed
|
|
955 // for the first loop iteration\&.
|
|
956 digitExponent = digitExponent + 1;
|
|
957 }
|
|
958 else
|
|
959 {
|
|
960 // The exponent estimate was correct\&.
|
|
961 // Multiply larger by the output base to prepare for the first loop iteration\&.
|
|
962 BigInt_Multiply10( &scaledValue );
|
|
963 BigInt_Multiply10( &scaledMarginLow );
|
|
964 if (pScaledMarginHigh != &scaledMarginLow)
|
|
965 BigInt_Multiply2( pScaledMarginHigh, scaledMarginLow );
|
|
966 }
|
|
967
|
|
968 // Compute the cutoff exponent (the exponent of the final digit to print)\&.
|
|
969 // Default to the maximum size of the output buffer\&.
|
|
970 tS32 cutoffExponent = digitExponent - bufferSize;
|
|
971 switch(cutoffMode)
|
|
972 {
|
|
973 // print digits until we pass the accuracy margin limits or buffer size
|
|
974 case CutoffMode_Unique:
|
|
975 break;
|
|
976
|
|
977 // print cutoffNumber of digits or until we reach the buffer size
|
|
978 case CutoffMode_TotalLength:
|
|
979 {
|
|
980 tS32 desiredCutoffExponent = digitExponent - (tS32)cutoffNumber;
|
|
981 if (desiredCutoffExponent > cutoffExponent)
|
|
982 cutoffExponent = desiredCutoffExponent;
|
|
983 }
|
|
984 break;
|
|
985
|
|
986 // print cutoffNumber digits past the decimal point or until we reach the buffer size
|
|
987 case CutoffMode_FractionLength:
|
|
988 {
|
|
989 tS32 desiredCutoffExponent = -(tS32)cutoffNumber;
|
|
990 if (desiredCutoffExponent > cutoffExponent)
|
|
991 cutoffExponent = desiredCutoffExponent;
|
|
992 }
|
|
993 break;
|
|
994 }
|
|
995
|
|
996 // Output the exponent of the first digit we will print
|
|
997 *pOutExponent = digitExponent-1;
|
|
998
|
|
999 // In preparation for calling BigInt_DivideWithRemainder_MaxQuotient9(),
|
|
1000 // we need to scale up our values such that the highest block of the denominator
|
|
1001 // is greater than or equal to 8\&. We also need to guarantee that the numerator
|
|
1002 // can never have a length greater than the denominator after each loop iteration\&.
|
|
1003 // This requires the highest block of the denominator to be less than or equal to
|
|
1004 // 429496729 which is the highest number that can be multiplied by 10 without
|
|
1005 // overflowing to a new block\&.
|
|
1006 RJ_ASSERT( scale\&.GetLength() > 0 );
|
|
1007 tU32 hiBlock = scale\&.GetBlock( scale\&.GetLength() - 1 );
|
|
1008 if (hiBlock < 8 || hiBlock > 429496729)
|
|
1009 {
|
|
1010 // Perform a bit shift on all values to get the highest block of the denominator into
|
|
1011 // the range [8,429496729]\&. We are more likely to make accurate quotient estimations
|
|
1012 // in BigInt_DivideWithRemainder_MaxQuotient9() with higher denominator values so
|
|
1013 // we shift the denominator to place the highest bit at index 27 of the highest block\&.
|
|
1014 // This is safe because (2^28 - 1) = 268435455 which is less than 429496729\&. This means
|
|
1015 // that all values with a highest bit at index 27 are within range\&.
|
|
1016 tU32 hiBlockLog2 = LogBase2(hiBlock);
|
|
1017 RJ_ASSERT(hiBlockLog2 < 3 || hiBlockLog2 > 27);
|
|
1018 tU32 shift = (32 + 27 - hiBlockLog2) % 32;
|
|
1019
|
|
1020 BigInt_ShiftLeft( &scale, shift );
|
|
1021 BigInt_ShiftLeft( &scaledValue, shift);
|
|
1022 BigInt_ShiftLeft( &scaledMarginLow, shift);
|
|
1023 if (pScaledMarginHigh != &scaledMarginLow)
|
|
1024 BigInt_Multiply2( pScaledMarginHigh, scaledMarginLow );
|
|
1025 }
|
|
1026
|
|
1027 // These values are used to inspect why the print loop terminated so we can properly
|
|
1028 // round the final digit\&.
|
|
1029 tB low; // did the value get within marginLow distance from zero
|
|
1030 tB high; // did the value get within marginHigh distance from one
|
|
1031 tU32 outputDigit; // current digit being output
|
|
1032
|
|
1033 if (cutoffMode == CutoffMode_Unique)
|
|
1034 {
|
|
1035 // For the unique cutoff mode, we will try to print until we have reached a level of
|
|
1036 // precision that uniquely distinguishes this value from its neighbors\&. If we run
|
|
1037 // out of space in the output buffer, we terminate early\&.
|
|
1038 for (;;)
|
|
1039 {
|
|
1040 digitExponent = digitExponent-1;
|
|
1041
|
|
1042 // divide out the scale to extract the digit
|
|
1043 outputDigit = BigInt_DivideWithRemainder_MaxQuotient9(&scaledValue, scale);
|
|
1044 RJ_ASSERT( outputDigit < 10 );
|
|
1045
|
|
1046 // update the high end of the value
|
|
1047 BigInt_Add( &scaledValueHigh, scaledValue, *pScaledMarginHigh );
|
|
1048
|
|
1049 // stop looping if we are far enough away from our neighboring values
|
|
1050 // or if we have reached the cutoff digit
|
|
1051 low = BigInt_Compare(scaledValue, scaledMarginLow) < 0;
|
|
1052 high = BigInt_Compare(scaledValueHigh, scale) > 0;
|
|
1053 if (low | high | (digitExponent == cutoffExponent))
|
|
1054 break;
|
|
1055
|
|
1056 // store the output digit
|
|
1057 *pCurDigit = (tC8)('0' + outputDigit);
|
|
1058 ++pCurDigit;
|
|
1059
|
|
1060 // multiply larger by the output base
|
|
1061 BigInt_Multiply10( &scaledValue );
|
|
1062 BigInt_Multiply10( &scaledMarginLow );
|
|
1063 if (pScaledMarginHigh != &scaledMarginLow)
|
|
1064 BigInt_Multiply2( pScaledMarginHigh, scaledMarginLow );
|
|
1065 }
|
|
1066 }
|
|
1067 else
|
|
1068 {
|
|
1069 // For length based cutoff modes, we will try to print until we
|
|
1070 // have exhausted all precision (i\&.e\&. all remaining digits are zeros) or
|
|
1071 // until we reach the desired cutoff digit\&.
|
|
1072 low = false;
|
|
1073 high = false;
|
|
1074
|
|
1075 for (;;)
|
|
1076 {
|
|
1077 digitExponent = digitExponent-1;
|
|
1078
|
|
1079 // divide out the scale to extract the digit
|
|
1080 outputDigit = BigInt_DivideWithRemainder_MaxQuotient9(&scaledValue, scale);
|
|
1081 RJ_ASSERT( outputDigit < 10 );
|
|
1082
|
|
1083 if ( scaledValue\&.IsZero() | (digitExponent == cutoffExponent) )
|
|
1084 break;
|
|
1085
|
|
1086 // store the output digit
|
|
1087 *pCurDigit = (tC8)('0' + outputDigit);
|
|
1088 ++pCurDigit;
|
|
1089
|
|
1090 // multiply larger by the output base
|
|
1091 BigInt_Multiply10(&scaledValue);
|
|
1092 }
|
|
1093 }
|
|
1094
|
|
1095 // round off the final digit
|
|
1096 // default to rounding down if value got too close to 0
|
|
1097 tB roundDown = low;
|
|
1098
|
|
1099 // if it is legal to round up and down
|
|
1100 if (low == high)
|
|
1101 {
|
|
1102 // round to the closest digit by comparing value with 0\&.5\&. To do this we need to convert
|
|
1103 // the inequality to large integer values\&.
|
|
1104 // compare( value, 0\&.5 )
|
|
1105 // compare( scale * value, scale * 0\&.5 )
|
|
1106 // compare( 2 * scale * value, scale )
|
|
1107 BigInt_Multiply2(&scaledValue);
|
|
1108 tS32 compare = BigInt_Compare(scaledValue, scale);
|
|
1109 roundDown = compare < 0;
|
|
1110
|
|
1111 // if we are directly in the middle, round towards the even digit (i\&.e\&. IEEE rouding rules)
|
|
1112 if (compare == 0)
|
|
1113 roundDown = (outputDigit & 1) == 0;
|
|
1114 }
|
|
1115
|
|
1116 // print the rounded digit
|
|
1117 if (roundDown)
|
|
1118 {
|
|
1119 *pCurDigit = (tC8)('0' + outputDigit);
|
|
1120 ++pCurDigit;
|
|
1121 }
|
|
1122 else
|
|
1123 {
|
|
1124 // handle rounding up
|
|
1125 if (outputDigit == 9)
|
|
1126 {
|
|
1127 // find the first non-nine prior digit
|
|
1128 for (;;)
|
|
1129 {
|
|
1130 // if we are at the first digit
|
|
1131 if (pCurDigit == pOutBuffer)
|
|
1132 {
|
|
1133 // output 1 at the next highest exponent
|
|
1134 *pCurDigit = '1';
|
|
1135 ++pCurDigit;
|
|
1136 *pOutExponent += 1;
|
|
1137 break;
|
|
1138 }
|
|
1139
|
|
1140 --pCurDigit;
|
|
1141 if (*pCurDigit != '9')
|
|
1142 {
|
|
1143 // increment the digit
|
|
1144 *pCurDigit += 1;
|
|
1145 ++pCurDigit;
|
|
1146 break;
|
|
1147 }
|
|
1148 }
|
|
1149 }
|
|
1150 else
|
|
1151 {
|
|
1152 // values in the range [0,8] can perform a simple round up
|
|
1153 *pCurDigit = (tC8)('0' + outputDigit + 1);
|
|
1154 ++pCurDigit;
|
|
1155 }
|
|
1156 }
|
|
1157
|
|
1158 // return the number of digits output
|
|
1159 RJ_ASSERT(pCurDigit - pOutBuffer <= (tPtrDiff)bufferSize);
|
|
1160 return pCurDigit - pOutBuffer;
|
|
1161 }
|
|
.fi
|
|
.SH "Author"
|
|
.PP
|
|
Generated automatically by Doxygen for amath from the source code\&.
|