I have recently learned about fixed-sized integer and am planning to use them in an old program I wrote years ago.
Is there any equivalent of fixed-sized int for float and/or double?
My plan is to use "native types" int,float,double
for the biggest part of the program and only specify fixed-size types when portability is a concern (like read/write with a binary file).
I use a binary file store data like: date yyyymmdd (so uint32
), flags [0,4] (so uint8
), string (null terminated string) and currencies (now it's double
).
Concerning portability, the program is "portable" is the sense that it can be compiled (or cross-compiled) and run on different platform. So far: linux, windows, android (natively, through a terminal emulator without GUI) and OpenBSD (strcat/strcpy only needs to be replaced by strlcat/strlcpy in 2 lines). I am concerned about what could happen to the stored float/double if I used the same binary data file between linux x86_64, android arm-something, windows 32 something, etc... I would like to have a way to enforce a unique size and representation of floating-point values in the binary file.
2 Answers 2
For currencies, suggests special handling. Select a fixed width integer type to meet range needs (int64_t
or int32_t
) and scale by smallest monetary unit. If code is only storing/reading values like 123.12
void Store_int32(int32_t x); // Handles int32_t in endian independent method
int32_t Get_int32(void); // Handles int32_t in endian independent method
void Store_Currency(double c) {
if (c < INT32_MIN/100.0 || c > INT32_MAX/100.0) Handle_RangeError();
Store_int32(round(c*100.0));
}
double Get_Currency(void) {
Get_int32()/100.0;
}
For general use of double
, use conversion to/from a textual hexadecimal (or decimal with sufficient precision) FP notation.
void Store_double(double c) {
char s[100];
sprintf(s, "%a", c); // 0x1.ec7ae147ae148p+6
// or
sprintf(s, "%.*e", DBL_DECIMAL_DIG - 1, c); // 1.2312000000000000e+02
Store_string(s);
}
double Get_double(void) {
char s[100];
Get_string(s, sizeof s);
double x;
sscanf(s, "%f", &x); // %f reads decimal and hexadecimal FP formats.
return x;
}
1 Comment
Most floating point is IEEE 754, 64 bit or 32 bit. However if the floating point unit in your processor is not compatible, there's no realistic, efficient way of making it compatible, and thus programs will produce slightly different results when run on different machines. (That's actually a good test for a sound program - if results are significantly different because of floating point errors, then you are handling floating point operations badly).
You can however load and save the closest representation to IEEE 754 in a binary file, portably. Code is maintained here here
4 Comments
stdint.h
that will work as expected on any compliant platform, than to rely on the very type that is assumed not to be reliable.
__STDC_IEC_559__
is defined, then yes, else no. Need more details on your FP portability requirements. Loosely: recommend store currencies as a string.