Douglas Crockford

Blog

Books

Videos

2023 Appearances

JavaScript

Misty

JSLint

JSON

Github

Electric Communities

Mastodon/Layer8

Flickr Photo Album

ResearchGate

LinkedIn

Pronouns: pe/per

About

DEC64: String Functions

DEC64

One of the most difficult problems in floating-point systems is the conversion of numbers to text. This conversion is important because humans generally cannot use binary representations, and there are not simple, exact transformations between familiar decimal representations and binary floating-point. It can be difficult and expensive to find representations that are accurate, minimal, and unsurprising.


  0.1 + 0.2 10 / 3 10.1 - 9.93
IEEE754
0.30000000000000004
3.3333333333333335
0.16999999999999993
DEC64
0.3
3.3333333333333333
0.17

One of DEC64's advantages is that it easily and accurately converts to decimal representations, requiring only slightly more effort than the conversion of integers.

dec64_string.c contains functions for converting DEC64 numbers to strings and back again. dec64_string.h includes C function prototypes for these functions:

dec64 dec64_from_string(
    dec64_string_state state,
    dec64_string_char string[]
)
dec64_string_state dec64_string_begin()
dec64_string_char dec64_string_decimal_point(
    dec64_string_state state,
    dec64_string_char decimal_point
)
void dec64_string_end(
    dec64_string_state state
)
void dec64_string_engineering(
    dec64_string_state state
)
int dec64_string_places(
    dec64_string_state state,
    dec64_string_char places
)
void dec64_string_scientific(
    dec64_string_state state
)
int dec64_string_separation(
    dec64_string_state state,
    int separation
)
dec64_string_char dec64_string_separator(
    dec64_string_state state,
    dec64_string_char separator
)
void dec64_string_standard(
    dec64_string_state state
)
int dec64_to_string(
    dec64_string_state state,
    dec64 number,
    dec64_string_char string[]
)

Two types are provided:

String State

The functions are reentrant and thread safe. This is accomplished by use of a state object that is created by dec64_string_begin and destroyed by dec64_string_end. All of the other functions require a state object as the first argument. The state argument allows for customizing the conversions. Do not attempt to modify the string state object directly. Use the provided functions instead. State objects are reusable.

The state object contains the output mode: standard, scientific, or engineering.

Creation

dec64_string_state dec64_string_begin()

dec64_string_begin creates a state object. The object should be passed to all of the other functions.

Destruction

void dec64_string_end(
    dec64_string_state state
)

dec64_string_end destroys and deallocates a state object.

Configuration

The following functions configure or customize a state object.

void dec64_string_standard(
    dec64_string_state state
)

Put dec64_to_string into standard mode. Separators can be inserted between some digits if requested. If the number might be too long, then scientific mode might be used instead.

Standard mode is the default.

void dec64_string_scientific(
    dec64_string_state state
)

Put dec64_to_string into scientific mode, in which the coefficient is displayed with one digit before the decimal point, and an exponent prefixed with 'e' is appended if necessary.

void dec64_string_engineering(
    dec64_string_state state
)

Put dec64_to_string into engineering mode, which is like scientific mode except that the exponent is constrained to be a multiple of 3. There can be up to three digits before the decimal point.

dec64_string_char dec64_string_decimal_point(
    dec64_string_state state,
    dec64_string_char decimal_point
)

Specify the decimal point character. This is used by both dec64_to_string and dec64_from_string. The default is '.'period. If it is '\0'nul, then the decimal point will be suppressed.

It returns the previous value.

int dec64_string_places(
    dec64_string_state state,
    dec64_string_char places
)

Specify the minimum number of decimal places output by dec64_to_string in standard mode. This is commonly used to format money values. The default is 0.

It returns the previous value.

dec64_string_char dec64_string_separator(
    dec64_string_state state,
    dec64_string_char separator
)

Specify the separation character, which is used by dec64_to_string in standard mode to improve the readability of digits before the decimal point. Typical values include

','comma
' 'space
'_'underbar
'.'period
'\0'nul

If it is '\0'nul, then separation will be suppressed. The default is '\0'nul.

dec64_from_string will ignore this character.

It returns the previous value.

int dec64_string_separation(
    dec64_string_state state,
    int separation
)

Specify the number of digits output between separators by dec64_to_string in standard mode. If separation is 1 or less, then separation is suppressed. The default is 3.

It returns the previous value.

Action

dec64 dec64_from_string(
    dec64_string_state state,
    dec64_string_char string[]
)

dec64_from_string converts a zero-delimited string into a dec64. Separator characters will be ignored. If conversion is not possible for any reason, the result will be DEC64_NAN.

int dec64_to_string(
    dec64_string_state state,
    dec64 number,
    dec64_string_char string[]
)

dec64_to_string converts a dec64 number into a string. The caller provides the memory into which to deposit the string. The provided string must have sufficient capacity to hold 32 characters. It returns the number of characters actually deposited in the string (not including the trailing '\0'). If the number is nan, then it returns 0 indicating an empty string. If NULL is passed in as the string, then no characters will be deposited, but a character count will be returned.

In standard mode, the number will be formatted conventionally unless it would require more than 17 digits, which would be due to excessive trailing zeros or zeros immediately after the decimal point. In that case scientific notation will be used instead.

Examples

dec64_string_state state = dec64_string_begin();
dec64_to_string(state, dec64_new(10, -128), string);
"1e-127"
dec64_to_string(state, dec64_new(1024, 0), string);
"1024"
dec64_separator(state, ',');
dec64_to_string(state, dec64_new(1024, 0), string);
"1,024"
dec64_separator(state, ' ');
dec64_to_string(state, dec64_new(1024, 0), string);
"1 024"
dec64_places(state, 4);
dec64_to_string(state, dec64_new(1024, 0), string);
"1 024.0000"
dec64_scientific(state);
dec64_to_string(state, dec64_new(1024, 0), string);
"1.024e3"
dec64_from_string(state, "1 024.0000")
1024
dec64_from_string(state, "1,024.0000")
DEC64_NAN
dec64_separator(state, ',');
dec64_from_string(state, "1,024.0000")
1024
dec64_string_end();