Implements a fixed size decimal nummber.
Decimal | Implements a fixed size decimal nummber. |
Copyright | This program is free software. |
Files | |
C-kern/ | Header file Decimal. |
C-kern/ | Implementation file Decimal impl. |
Functions | |
test | |
unittest_math_float_decimal | Test interface of decimal_t. |
decimal_t | Represents a decimal number with at most 1143 decimal digits. |
size_allocated | The number of allocated integers in digits. |
sign_and_used_digits | The sign of this variable is the sign of the number. |
exponent | The exponent of base number 1000000000. |
digits | 9 decimal digits encoded as integer are stored per digit (uint32_t). |
lifetime | |
new_decimal | Allocates a new decimal number. |
newcopy_decimal | Allocates a new decimal number and initializes its value with a copy of copyfrom. |
delete_decimal | Frees any allocated memory and sets (*dec) to 0. |
query | |
bitsperint_decimal | Returns the size in bytes of the internally used integer type. |
cmp_decimal | Compares two decimal numbers and returns result. |
cmpmagnitude_decimal | Compares magnitude of two decimal numbers returns result. |
digitsperint_decimal | Returns the number of decimal digits stored internally per integer. |
exponent_decimal | Returns the decimal exponent of the number. |
expmax_decimal | Returns the maximum magnitude of the decimal exponent. |
first9digits_decimal | Returns the 9 most significant decimal digits with correct sign. |
first18digits_decimal | Returns the 18 most significant decimal digits with correct sign. |
isnegative_decimal | Returns true if dec is negative else false. |
iszero_decimal | Returns true if dec has value 0 else false. |
nrdigits_decimal | Returns the number of decimal digits stored. |
nrdigitsmax_decimal | Returns the maximum number of decimal digits supported by a decimal_t. |
sign_decimal | Returns -1, 0 or +1 if dec is negative, zero or positive. |
size_decimal | Returns number of integers needed to store all decimal digits. |
sizemax_decimal | Returns the maximum number of integers which can be allocated. |
tocstring_decimal | Converts dec to cstring_t. |
assign | |
clear_decimal | Sets the value to 0. |
copy_decimal | Copies the value from copyfrom to dec. |
setfromint32_decimal | Sets decimal to value mutliplied by pow(10,*decimal_exponent*). |
setfromint64_decimal | Sets decimal to value mutliplied by pow(10,*decimal_exponent*). |
setfromfloat_decimal | Sets decimal to floating point value. |
setfromchar_decimal | Sets decimal dec to the value represented in decimal/scientific notation. |
unary operations | |
negate_decimal | Inverts the sign of the number. |
setnegative_decimal | Changes the sign to be negative. |
setpositive_decimal | Changes the sign to be positive. |
ternary operations | |
add_decimal | Adds the last two parameters and returns the sum in the first. |
sub_decimal | Subracts the third from the second parameter and returns the difference in the first. |
mult_decimal | Multiplies the two last parameters and returns the product in the first. |
div_decimal | Divides parameter ldec by rdec and returns the quotient in the first. |
divi32_decimal | Divides parameter ldec by rdivisor and returns quotient in the first. |
inline implementation | |
Macros | |
bitsperint_decimal | Implements decimal_t.bitsperint_decimal. |
digitsperint_decimal | Implements decimal_t.digitsperint_decimal. |
expmax_decimal | Implements decimal_t.expmax_decimal. |
exponent_decimal | Implements decimal_t.exponent_decimal. |
isnegative_decimal | Implements decimal_t.isnegative_decimal. |
iszero_decimal | Implements decimal_t.iszero_decimal. |
negate_decimal | Implements decimal_t.negate_decimal. |
nrdigitsmax_decimal | Implements decimal_t.nrdigitsmax_decimal. |
setnegative_decimal | Implements decimal_t.setnegative_decimal. |
Functions | |
setpositive_decimal | Implements decimal_t.setpositive_decimal. |
Macros | |
sign_decimal | Implements decimal_t.sign_decimal. |
size_decimal | Implements decimal_t.size_decimal. |
sizemax_decimal | Implements decimal_t.sizemax_decimal. |
This program is free software. You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
© 2012 Jörg Seebohn
Header file Decimal.
Implementation file Decimal impl.
test | |
unittest_math_float_decimal | Test interface of decimal_t. |
int unittest_math_float_decimal( void )
Test interface of decimal_t.
struct decimal_t
Represents a decimal number with at most 1143 decimal digits. The decimal exponent must be in the range [-expmax_decimal..+<expmax_decimal>], where expmax_decimal returns the value digitsperint_decimal*INT16_MAX (==9*32767).
The exponent is always aligned to the next lower multiple of digitsperint_decimal. The reason for the alignment is to allow binary operations on decimals without any need for shifting the decimal number of one operand by a power of 10.
The number is represented internally as a number of integer digits and a exponent. Every integer digit contains a value in the range [0..999999999]. The representation of the number is to the base 1000000000. The value of a decimal_t number can be determined with:
double calc_value(decimal_t * dec) { // it is possible that double over- or underflows. double value = 0 ; uint32_t base = pow(10, digitsperint_decimal()) ; for (uint8_t i = 0; i < size_decimal(dec); ++i) value += dec->digits[i] * pow(base, i) ; return pow(10, exponent_decimal(dec)) * value * sign_decimal(dec) ; }
The result parameter of an operation is reallocated in case the preallocated size is not big enough and if it is of type pointer to pointer to decimal_t. In case of an error the result parameter will be either left untouched, contains the correct result, or it will be cleared. Clearing the result is necessary if it is computed digit by digit and an error occurs before the last digit could be computed.
EOVERFLOW | This error can have following reasons. The value of the decimal exponent is outside the range of [-expmax_decimal..+<expmax_decimal>]. The number of digits to represent the result exactly is bigger than the value returned from nrdigitsmax_decimal, except for the division which has an extra parameter to round the result to a certain precision. |
ENOMEM | Every operation which produces more decimal digits than preallocted needs to reallocate the result parameter. If this reallocation fails ENOMEM is returned and the result is not changed. |
EINVAL | One input parameter is not valid (syntax error in input string in setfromchar_decimal or precision parameter either 0 or bigger than nrdigitsmax_decimal in div_decimal ...). |
size_allocated | The number of allocated integers in digits. |
sign_and_used_digits | The sign of this variable is the sign of the number. |
exponent | The exponent of base number 1000000000. |
digits | 9 decimal digits encoded as integer are stored per digit (uint32_t). |
lifetime | |
new_decimal | Allocates a new decimal number. |
newcopy_decimal | Allocates a new decimal number and initializes its value with a copy of copyfrom. |
delete_decimal | Frees any allocated memory and sets (*dec) to 0. |
query | |
bitsperint_decimal | Returns the size in bytes of the internally used integer type. |
cmp_decimal | Compares two decimal numbers and returns result. |
cmpmagnitude_decimal | Compares magnitude of two decimal numbers returns result. |
digitsperint_decimal | Returns the number of decimal digits stored internally per integer. |
exponent_decimal | Returns the decimal exponent of the number. |
expmax_decimal | Returns the maximum magnitude of the decimal exponent. |
first9digits_decimal | Returns the 9 most significant decimal digits with correct sign. |
first18digits_decimal | Returns the 18 most significant decimal digits with correct sign. |
isnegative_decimal | Returns true if dec is negative else false. |
iszero_decimal | Returns true if dec has value 0 else false. |
nrdigits_decimal | Returns the number of decimal digits stored. |
nrdigitsmax_decimal | Returns the maximum number of decimal digits supported by a decimal_t. |
sign_decimal | Returns -1, 0 or +1 if dec is negative, zero or positive. |
size_decimal | Returns number of integers needed to store all decimal digits. |
sizemax_decimal | Returns the maximum number of integers which can be allocated. |
tocstring_decimal | Converts dec to cstring_t. |
assign | |
clear_decimal | Sets the value to 0. |
copy_decimal | Copies the value from copyfrom to dec. |
setfromint32_decimal | Sets decimal to value mutliplied by pow(10,*decimal_exponent*). |
setfromint64_decimal | Sets decimal to value mutliplied by pow(10,*decimal_exponent*). |
setfromfloat_decimal | Sets decimal to floating point value. |
setfromchar_decimal | Sets decimal dec to the value represented in decimal/scientific notation. |
unary operations | |
negate_decimal | Inverts the sign of the number. |
setnegative_decimal | Changes the sign to be negative. |
setpositive_decimal | Changes the sign to be positive. |
ternary operations | |
add_decimal | Adds the last two parameters and returns the sum in the first. |
sub_decimal | Subracts the third from the second parameter and returns the difference in the first. |
mult_decimal | Multiplies the two last parameters and returns the product in the first. |
div_decimal | Divides parameter ldec by rdec and returns the quotient in the first. |
divi32_decimal | Divides parameter ldec by rdivisor and returns quotient in the first. |
uint8_t size_allocated
The number of allocated integers in digits. This number is always lower or equal than 0x7f (INT8_MAX). The reason is that sign_and_used_digits is signed and therefore only 7 bits can be used to represent the magnitude.
int8_t sign_and_used_digits
The sign of this variable is the sign of the number. The magnitude gives the number of used integers in digits. One such integer represents 9 decimal digits.
int16_t exponent
The exponent of base number 1000000000. To get a decimal exponent multiply this number with digitsperint_decimal. The value of the exponentiation is calculated as pow(10,<digitsperint_decimal>*exponent).
uint32_t digits[/*0..size_allocated-1*/]
9 decimal digits encoded as integer are stored per digit (uint32_t). The value of every digit is in the range [0 .. 999999999]. The value of digits[i+1] must be multiplied with pow(10, digitsperint_decimal()) before it can be added to digits[i]. Only digits[i] with i < abs(sign_and_used_digits) are valid.
int new_decimal( /*out*/decimal_t ** dec, uint32_t nrdigits )
Allocates a new decimal number. The value is initialized to zero. The maximum number of supported decimal digits is 1143 (9 * INT8_MAX). The newly allocated object always can represent at least 9 decimal digits (digitsperint_decimal). To uniquely represent a double you need at least 17 digits. For a float you need in same rare cases 9 digits.
int cmpmagnitude_decimal( const decimal_t * ldec, const decimal_t * rdec )
Compares magnitude of two decimal numbers returns result. This function is the same as cmp_decimal except that the sign of both numbers is considered to be positive.
-1 | Absolute value of ldec is lower than absolute value of rdec |
0 | Both absolute values are equal |
+1 | Absolute value of ldec is greater than absolute value of rdec |
int32_t exponent_decimal( const decimal_t * dec )
Returns the decimal exponent of the number. The returned value is in the range [-expmax_decimal..+<expmax_decimal>].
int32_t expmax_decimal( void )
Returns the maximum magnitude of the decimal exponent. The returned value is digitsperint_decimal*INT16_MAX (==9*32767).
uint16_t nrdigitsmax_decimal( void )
Returns the maximum number of decimal digits supported by a decimal_t.
uint8_t size_decimal( decimal_t * dec )
Returns number of integers needed to store all decimal digits. Every integer can store up to digitsperint_decimal decimal digits.
int tocstring_decimal( const decimal_t * dec, struct cstring_t * cstr )
Converts dec to cstring_t. The result is returned in the already initialized parameter cstr. If during conversion an error occurs cstr is set to the empty string.
int setfromint32_decimal( decimal_t *restrict * dec, int32_t value, int32_t decimal_exponent )
Sets decimal to value mutliplied by pow(10,*decimal_exponent*). See decimal_t for a description of the error codes.
int setfromint64_decimal( decimal_t *restrict * dec, int64_t value, int32_t decimal_exponent )
Sets decimal to value mutliplied by pow(10,*decimal_exponent*). See decimal_t for a description of the error codes.
int setfromfloat_decimal( decimal_t *restrict * dec, float value )
Sets decimal to floating point value. See decimal_t for a description of the error codes.
int setfromchar_decimal( decimal_t *restrict * dec, const size_t nrchars, const char decimalstr[nrchars] )
Sets decimal dec to the value represented in decimal/scientific notation. The character string must be of the format “[-]ddd.ddde±dd” where d is a digit from “0”-”9”. The base 10 exponent value is started with e followed by an optional sign and one or more digots. The parsing of the string takes no localization into account. The string is considered to be in utf8 encoding.
int add_decimal( decimal_t *restrict * result, const decimal_t * ldec, const decimal_t * rdec )
Adds the last two parameters and returns the sum in the first. See decimal_t for a discussion of the result parameter.
int sub_decimal( decimal_t *restrict * result, const decimal_t * ldec, const decimal_t * rdec )
Subracts the third from the second parameter and returns the difference in the first. See decimal_t for a discussion of the result parameter.
int mult_decimal( decimal_t *restrict * result, const decimal_t * ldec, const decimal_t * rdec )
Multiplies the two last parameters and returns the product in the first. See decimal_t for a discussion of the result parameter.
int div_decimal( decimal_t *restrict * result, const decimal_t * ldec, const decimal_t * rdec, uint8_t result_size )
Divides parameter ldec by rdec and returns the quotient in the first. See decimal_t for a discussion of the result parameter. The last parameter result_size gives the number of decimal digits of the result in multiple of digitsperint_decimal. A value of 1 results in size_decimal(*result) returning 1. If this value is bigger than sizemax_decimal it is silently set to sizemax_decimal.
1. Calculating »1/3« with nrdigits_result==5 results in »0.33333«. 2. Calculating »12345/1« with nrdigits_result=4 results in »1234.0«. 3. Calculating »12355/1« with nrdigits_result=4 results in »1236.0«.
It is necessary to compute the result of the division to determine if a range overflow of the decimal exponent occurs for the given precision. In this case the partially computed result is cleared before return. (TODO: check if this is necessary)
If the digit after nrdigits_result is less than 5 the returned value is rounded down. If the digit after nrdigits_result is greater than 5 (or equal to 5 and the digits after it are not 0) the returned value is rounded up. If the digit after nrdigits_result is equal to 5 and all following digits are 0 the returned value is only rounded up if the last digit in result is odd.
int divi32_decimal( decimal_t *restrict * result, const decimal_t * ldec, int32_t rdivisor, uint8_t result_size )
Divides parameter ldec by rdivisor and returns quotient in the first. See div_decimal for a description of the last parameter. The absolute value of rdivisor must be in the range [1..pow(10,digitsperint_decimal())].
Macros | |
bitsperint_decimal | Implements decimal_t.bitsperint_decimal. |
digitsperint_decimal | Implements decimal_t.digitsperint_decimal. |
expmax_decimal | Implements decimal_t.expmax_decimal. |
exponent_decimal | Implements decimal_t.exponent_decimal. |
isnegative_decimal | Implements decimal_t.isnegative_decimal. |
iszero_decimal | Implements decimal_t.iszero_decimal. |
negate_decimal | Implements decimal_t.negate_decimal. |
nrdigitsmax_decimal | Implements decimal_t.nrdigitsmax_decimal. |
setnegative_decimal | Implements decimal_t.setnegative_decimal. |
Functions | |
setpositive_decimal | Implements decimal_t.setpositive_decimal. |
Macros | |
sign_decimal | Implements decimal_t.sign_decimal. |
size_decimal | Implements decimal_t.size_decimal. |
sizemax_decimal | Implements decimal_t.sizemax_decimal. |
#define bitsperint_decimal( ) ((uint8_t)(bitsof(((decimal_t*)0)->digits[0])))
Implements decimal_t.bitsperint_decimal.
#define digitsperint_decimal( ) ((uint8_t)(9 * bitsperint_decimal()/32))
Implements decimal_t.digitsperint_decimal.
#define expmax_decimal( dec ) ((int32_t)INT16_MAX * digitsperint_decimal())
Implements decimal_t.expmax_decimal.
#define exponent_decimal( dec ) ((int32_t)(dec)->exponent * digitsperint_decimal())
Implements decimal_t.exponent_decimal.
Implements decimal_t.isnegative_decimal.
#define iszero_decimal( dec ) ((dec)->sign_and_used_digits == 0)
Implements decimal_t.iszero_decimal.
#define negate_decimal( dec ) do { (dec)->sign_and_used_digits = (int8_t) ( - (dec)->sign_and_used_digits) ; } while (0)
Implements decimal_t.negate_decimal.
#define nrdigitsmax_decimal( ) ((uint16_t)(digitsperint_decimal() * sizemax_decimal()))
Implements decimal_t.nrdigitsmax_decimal.
#define setnegative_decimal( dec ) do { (dec)->sign_and_used_digits = (int8_t) ( (dec)->sign_and_used_digits < 0 ? (dec)->sign_and_used_digits : - (dec)->sign_and_used_digits ) ; } while (0)
Implements decimal_t.setnegative_decimal.
#define setpositive_decimal( dec ) do
Implements decimal_t.setpositive_decimal.
Implements decimal_t.sign_decimal.
#define size_decimal( dec ) ((uint8_t)( (dec)->sign_and_used_digits < 0 ? - (dec)->sign_and_used_digits : (dec)->sign_and_used_digits))
Implements decimal_t.size_decimal.
#define sizemax_decimal( ) ((uint8_t)127)
Implements decimal_t.sizemax_decimal.
Test interface of decimal_t.
int unittest_math_float_decimal( void )
Represents a decimal number with at most 1143 decimal digits.
struct decimal_t
The number of allocated integers in digits.
uint8_t size_allocated
9 decimal digits encoded as integer are stored per digit (uint32_t).
uint32_t digits[/*0..size_allocated-1*/]
The sign of this variable is the sign of the number.
int8_t sign_and_used_digits
The exponent of base number 1000000000.
int16_t exponent
Allocates a new decimal number.
int new_decimal( /*out*/decimal_t ** dec, uint32_t nrdigits )
Allocates a new decimal number and initializes its value with a copy of copyfrom.
int newcopy_decimal( /*out*/decimal_t ** dec, const decimal_t * copyfrom )
Frees any allocated memory and sets (*dec) to 0.
int delete_decimal( decimal_t ** dec )
Returns the size in bytes of the internally used integer type.
uint8_t bitsperint_decimal( void )
Compares two decimal numbers and returns result.
int cmp_decimal( const decimal_t * ldec, const decimal_t * rdec )
Compares magnitude of two decimal numbers returns result.
int cmpmagnitude_decimal( const decimal_t * ldec, const decimal_t * rdec )
Returns the number of decimal digits stored internally per integer.
uint8_t digitsperint_decimal( void )
Returns the decimal exponent of the number.
int32_t exponent_decimal( const decimal_t * dec )
Returns the maximum magnitude of the decimal exponent.
int32_t expmax_decimal( void )
Returns the 9 most significant decimal digits with correct sign.
int32_t first9digits_decimal( decimal_t * dec, int32_t * decimal_exponent )
Returns the 18 most significant decimal digits with correct sign.
int64_t first18digits_decimal( decimal_t * dec, int32_t * decimal_exponent )
Returns true if dec is negative else false.
bool isnegative_decimal( const decimal_t * dec )
Returns true if dec has value 0 else false.
bool iszero_decimal( const decimal_t * dec )
Returns the number of decimal digits stored.
uint16_t nrdigits_decimal( const decimal_t * dec )
Returns the maximum number of decimal digits supported by a decimal_t.
uint16_t nrdigitsmax_decimal( void )
Returns -1, 0 or +1 if dec is negative, zero or positive.
int sign_decimal( const decimal_t * dec )
Returns number of integers needed to store all decimal digits.
uint8_t size_decimal( decimal_t * dec )
Returns the maximum number of integers which can be allocated.
uint8_t sizemax_decimal( void )
Converts dec to cstring_t.
int tocstring_decimal( const decimal_t * dec, struct cstring_t * cstr )
Dynamically growing C string with trailing ‘\0’ byte.
struct cstring_t
Sets the value to 0.
void clear_decimal( decimal_t * dec )
Copies the value from copyfrom to dec.
int copy_decimal( decimal_t *restrict * dec, const decimal_t * restrict copyfrom )
Sets decimal to value mutliplied by pow(10,*decimal_exponent*).
int setfromint32_decimal( decimal_t *restrict * dec, int32_t value, int32_t decimal_exponent )
Sets decimal to value mutliplied by pow(10,*decimal_exponent*).
int setfromint64_decimal( decimal_t *restrict * dec, int64_t value, int32_t decimal_exponent )
Sets decimal to floating point value.
int setfromfloat_decimal( decimal_t *restrict * dec, float value )
Sets decimal dec to the value represented in decimal/scientific notation.
int setfromchar_decimal( decimal_t *restrict * dec, const size_t nrchars, const char decimalstr[nrchars] )
Inverts the sign of the number.
void negate_decimal( decimal_t * dec )
Changes the sign to be negative.
void setnegative_decimal( decimal_t * dec )
Changes the sign to be positive.
void setpositive_decimal( decimal_t * dec )
Adds the last two parameters and returns the sum in the first.
int add_decimal( decimal_t *restrict * result, const decimal_t * ldec, const decimal_t * rdec )
Subracts the third from the second parameter and returns the difference in the first.
int sub_decimal( decimal_t *restrict * result, const decimal_t * ldec, const decimal_t * rdec )
Multiplies the two last parameters and returns the product in the first.
int mult_decimal( decimal_t *restrict * result, const decimal_t * ldec, const decimal_t * rdec )
Divides parameter ldec by rdec and returns the quotient in the first.
int div_decimal( decimal_t *restrict * result, const decimal_t * ldec, const decimal_t * rdec, uint8_t result_size )
Divides parameter ldec by rdivisor and returns quotient in the first.
int divi32_decimal( decimal_t *restrict * result, const decimal_t * ldec, int32_t rdivisor, uint8_t result_size )
Implements decimal_t.bitsperint_decimal.
#define bitsperint_decimal( ) ((uint8_t)(bitsof(((decimal_t*)0)->digits[0])))
Implements decimal_t.digitsperint_decimal.
#define digitsperint_decimal( ) ((uint8_t)(9 * bitsperint_decimal()/32))
Implements decimal_t.expmax_decimal.
#define expmax_decimal( dec ) ((int32_t)INT16_MAX * digitsperint_decimal())
Implements decimal_t.exponent_decimal.
#define exponent_decimal( dec ) ((int32_t)(dec)->exponent * digitsperint_decimal())
Implements decimal_t.iszero_decimal.
#define iszero_decimal( dec ) ((dec)->sign_and_used_digits == 0)
Implements decimal_t.negate_decimal.
#define negate_decimal( dec ) do { (dec)->sign_and_used_digits = (int8_t) ( - (dec)->sign_and_used_digits) ; } while (0)
Implements decimal_t.nrdigitsmax_decimal.
#define nrdigitsmax_decimal( ) ((uint16_t)(digitsperint_decimal() * sizemax_decimal()))
Implements decimal_t.setnegative_decimal.
#define setnegative_decimal( dec ) do { (dec)->sign_and_used_digits = (int8_t) ( (dec)->sign_and_used_digits < 0 ? (dec)->sign_and_used_digits : - (dec)->sign_and_used_digits ) ; } while (0)
Implements decimal_t.setpositive_decimal.
#define setpositive_decimal( dec ) do
Implements decimal_t.size_decimal.
#define size_decimal( dec ) ((uint8_t)( (dec)->sign_and_used_digits < 0 ? - (dec)->sign_and_used_digits : (dec)->sign_and_used_digits))
Implements decimal_t.sizemax_decimal.
#define sizemax_decimal( ) ((uint8_t)127)