// file: PrintFullFraction.c
//
// compile with gcc 4.6.2 or better:
// gcc -Wall -Wextra -std=c99 -O2 PrintFullFraction.c -o PrintFullFraction.exe
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <assert.h>
#if FLT_RADIX != 2
#error currently supported only FLT_RADIX = 2
#endif
int FractionalDigits(double d)
{
char buf[
1 + // sign, '-' or '+'
(sizeof(d) * CHAR_BIT + 3) / 4 + // mantissa hex digits max
1 + // decimal point, '.'
1 + // mantissa-exponent separator, 'p'
1 + // mantissa sign, '-' or '+'
(sizeof(d) * CHAR_BIT + 2) / 3 + // exponent decimal digits max
1 // string terminator, '\0'
];
int n;
char *pp, *p;
int e, lsbFound, lsbPos;
// convert d into "+/- 0x h.hhhh p +/- ddd" representation and check for errors
if ((n
= snprintf(buf
, sizeof(buf
), "%+a", d
)) < 0 || (unsigned)n >= sizeof(buf))
return -1;
//printf("{%s}", buf);
// make sure the conversion didn't produce something like "nan" or "inf"
// instead of "+/- 0x h.hhhh p +/- ddd"
if (strstr(buf
, "0x") != buf
+ 1 || (pp
= strchr(buf
, 'p')) == NULL
) return 0;
// extract the base-2 exponent manually, checking for overflows
e = 0;
p = pp + 1 + (pp[1] == '-' || pp[1] == '+'); // skip the exponent sign at first
for (; *p != '\0'; p++)
{
if (e > INT_MAX / 10)
return -2;
e *= 10;
if (e > INT_MAX - (*p - '0'))
return -2;
e += *p - '0';
}
if (pp[1] == '-') // apply the sign to the exponent
e = -e;
//printf("[%s|%d]", buf, e);
// find the position of the least significant non-zero bit
lsbFound = lsbPos = 0;
for (p = pp - 1; *p != 'x'; p--)
{
if (*p == '.')
continue;
if (!lsbFound)
{
int hdigit = (*p >= 'a') ? (*p - 'a' + 10) : (*p - '0'); // assuming ASCII chars
if (hdigit)
{
static const int lsbPosInNibble[16] = { 0,4,3,4, 2,4,3,4, 1,4,3,4, 2,4,3,4 };
lsbFound = 1;
lsbPos = -lsbPosInNibble[hdigit];
}
}
else
{
lsbPos -= 4;
}
}
lsbPos += 4;
if (!lsbFound)
return 0; // d is 0 (integer)
// adjust the least significant non-zero bit position
// by the base-2 exponent (just add them), checking
// for overflows
if (lsbPos >= 0 && e >= 0)
return 0; // lsbPos + e >= 0, d is integer
if (lsbPos < 0 && e < 0)
if (lsbPos < INT_MIN - e)
return -2; // d isn't integer and needs too many fractional digits
if ((lsbPos += e) >= 0)
return 0; // d is integer
if (lsbPos == INT_MIN && -INT_MAX != INT_MIN)
return -2; // d isn't integer and needs too many fractional digits
return -lsbPos;
}
const double testData[] =
{
0,
1, // 2 ^ 0
0.5, // 2 ^ -1
0.25, // 2 ^ -2
0.125,
0.0625, // ...
0.03125,
0.015625,
0.0078125, // 2 ^ -7
1.0/256, // 2 ^ -8
1.0/256/256, // 2 ^ -16
1.0/256/256/256, // 2 ^ -24
1.0/256/256/256/256, // 2 ^ -32
1.0/256/256/256/256/256/256/256/256, // 2 ^ -64
3.14159265358979323846264338327950288419716939937510582097494459,
0.1,
INFINITY,
#ifdef NAN
NAN,
#endif
DBL_MIN
};
int main(void)
{
unsigned i;
for (i = 0; i < sizeof(testData) / sizeof(testData[0]); i++)
{
int digits = FractionalDigits(testData[i]);
printf("%f %e %.*f\n", testData
[i
], testData
[i
], digits
, testData
[i
]); }
return 0;
}
Ly8gZmlsZTogUHJpbnRGdWxsRnJhY3Rpb24uYwovLwovLyBjb21waWxlIHdpdGggZ2NjIDQuNi4yIG9yIGJldHRlcjoKLy8gICBnY2MgLVdhbGwgLVdleHRyYSAtc3RkPWM5OSAtTzIgUHJpbnRGdWxsRnJhY3Rpb24uYyAtbyBQcmludEZ1bGxGcmFjdGlvbi5leGUKI2luY2x1ZGUgPGxpbWl0cy5oPgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHN0cmluZy5oPgojaW5jbHVkZSA8c3RkbGliLmg+CiNpbmNsdWRlIDxtYXRoLmg+CiNpbmNsdWRlIDxmbG9hdC5oPgojaW5jbHVkZSA8YXNzZXJ0Lmg+CgojaWYgRkxUX1JBRElYICE9IDIKI2Vycm9yIGN1cnJlbnRseSBzdXBwb3J0ZWQgb25seSBGTFRfUkFESVggPSAyCiNlbmRpZgoKaW50IEZyYWN0aW9uYWxEaWdpdHMoZG91YmxlIGQpCnsKICBjaGFyIGJ1ZlsKICAgICAgICAgICAxICsgLy8gc2lnbiwgJy0nIG9yICcrJwogICAgICAgICAgIChzaXplb2YoZCkgKiBDSEFSX0JJVCArIDMpIC8gNCArIC8vIG1hbnRpc3NhIGhleCBkaWdpdHMgbWF4CiAgICAgICAgICAgMSArIC8vIGRlY2ltYWwgcG9pbnQsICcuJwogICAgICAgICAgIDEgKyAvLyBtYW50aXNzYS1leHBvbmVudCBzZXBhcmF0b3IsICdwJwogICAgICAgICAgIDEgKyAvLyBtYW50aXNzYSBzaWduLCAnLScgb3IgJysnCiAgICAgICAgICAgKHNpemVvZihkKSAqIENIQVJfQklUICsgMikgLyAzICsgLy8gZXhwb25lbnQgZGVjaW1hbCBkaWdpdHMgbWF4CiAgICAgICAgICAgMSAvLyBzdHJpbmcgdGVybWluYXRvciwgJ1wwJwogICAgICAgICAgXTsKICBpbnQgbjsKICBjaGFyICpwcCwgKnA7CiAgaW50IGUsIGxzYkZvdW5kLCBsc2JQb3M7CgogIC8vIGNvbnZlcnQgZCBpbnRvICIrLy0gMHggaC5oaGhoIHAgKy8tIGRkZCIgcmVwcmVzZW50YXRpb24gYW5kIGNoZWNrIGZvciBlcnJvcnMKICBpZiAoKG4gPSBzbnByaW50ZihidWYsIHNpemVvZihidWYpLCAiJSthIiwgZCkpIDwgMCB8fAogICAgICAodW5zaWduZWQpbiA+PSBzaXplb2YoYnVmKSkKICAgIHJldHVybiAtMTsKCi8vcHJpbnRmKCJ7JXN9IiwgYnVmKTsKCiAgLy8gbWFrZSBzdXJlIHRoZSBjb252ZXJzaW9uIGRpZG4ndCBwcm9kdWNlIHNvbWV0aGluZyBsaWtlICJuYW4iIG9yICJpbmYiCiAgLy8gaW5zdGVhZCBvZiAiKy8tIDB4IGguaGhoaCBwICsvLSBkZGQiCiAgaWYgKHN0cnN0cihidWYsICIweCIpICE9IGJ1ZiArIDEgfHwKICAgICAgKHBwID0gc3RyY2hyKGJ1ZiwgJ3AnKSkgPT0gTlVMTCkKICAgIHJldHVybiAwOwoKICAvLyBleHRyYWN0IHRoZSBiYXNlLTIgZXhwb25lbnQgbWFudWFsbHksIGNoZWNraW5nIGZvciBvdmVyZmxvd3MKICBlID0gMDsKICBwID0gcHAgKyAxICsgKHBwWzFdID09ICctJyB8fCBwcFsxXSA9PSAnKycpOyAvLyBza2lwIHRoZSBleHBvbmVudCBzaWduIGF0IGZpcnN0CiAgZm9yICg7ICpwICE9ICdcMCc7IHArKykKICB7CiAgICBpZiAoZSA+IElOVF9NQVggLyAxMCkKICAgICAgcmV0dXJuIC0yOwogICAgZSAqPSAxMDsKICAgIGlmIChlID4gSU5UX01BWCAtICgqcCAtICcwJykpCiAgICAgIHJldHVybiAtMjsKICAgIGUgKz0gKnAgLSAnMCc7CiAgfQogIGlmIChwcFsxXSA9PSAnLScpIC8vIGFwcGx5IHRoZSBzaWduIHRvIHRoZSBleHBvbmVudAogICAgZSA9IC1lOwoKLy9wcmludGYoIlslc3wlZF0iLCBidWYsIGUpOwoKICAvLyBmaW5kIHRoZSBwb3NpdGlvbiBvZiB0aGUgbGVhc3Qgc2lnbmlmaWNhbnQgbm9uLXplcm8gYml0CiAgbHNiRm91bmQgPSBsc2JQb3MgPSAwOwogIGZvciAocCA9IHBwIC0gMTsgKnAgIT0gJ3gnOyBwLS0pCiAgewogICAgaWYgKCpwID09ICcuJykKICAgICAgY29udGludWU7CiAgICBpZiAoIWxzYkZvdW5kKQogICAgewogICAgICBpbnQgaGRpZ2l0ID0gKCpwID49ICdhJykgPyAoKnAgLSAnYScgKyAxMCkgOiAoKnAgLSAnMCcpOyAvLyBhc3N1bWluZyBBU0NJSSBjaGFycwogICAgICBpZiAoaGRpZ2l0KQogICAgICB7CiAgICAgICAgc3RhdGljIGNvbnN0IGludCBsc2JQb3NJbk5pYmJsZVsxNl0gPSB7IDAsNCwzLDQsICAyLDQsMyw0LCAxLDQsMyw0LCAyLDQsMyw0IH07CiAgICAgICAgbHNiRm91bmQgPSAxOwogICAgICAgIGxzYlBvcyA9IC1sc2JQb3NJbk5pYmJsZVtoZGlnaXRdOwogICAgICB9CiAgICB9CiAgICBlbHNlCiAgICB7CiAgICAgIGxzYlBvcyAtPSA0OwogICAgfQogIH0KICBsc2JQb3MgKz0gNDsKCiAgaWYgKCFsc2JGb3VuZCkKICAgIHJldHVybiAwOyAvLyBkIGlzIDAgKGludGVnZXIpCgogIC8vIGFkanVzdCB0aGUgbGVhc3Qgc2lnbmlmaWNhbnQgbm9uLXplcm8gYml0IHBvc2l0aW9uCiAgLy8gYnkgdGhlIGJhc2UtMiBleHBvbmVudCAoanVzdCBhZGQgdGhlbSksIGNoZWNraW5nCiAgLy8gZm9yIG92ZXJmbG93cwoKICBpZiAobHNiUG9zID49IDAgJiYgZSA+PSAwKQogICAgcmV0dXJuIDA7IC8vIGxzYlBvcyArIGUgPj0gMCwgZCBpcyBpbnRlZ2VyCgogIGlmIChsc2JQb3MgPCAwICYmIGUgPCAwKQogICAgaWYgKGxzYlBvcyA8IElOVF9NSU4gLSBlKQogICAgICByZXR1cm4gLTI7IC8vIGQgaXNuJ3QgaW50ZWdlciBhbmQgbmVlZHMgdG9vIG1hbnkgZnJhY3Rpb25hbCBkaWdpdHMKCiAgaWYgKChsc2JQb3MgKz0gZSkgPj0gMCkKICAgIHJldHVybiAwOyAvLyBkIGlzIGludGVnZXIKCiAgaWYgKGxzYlBvcyA9PSBJTlRfTUlOICYmIC1JTlRfTUFYICE9IElOVF9NSU4pCiAgICByZXR1cm4gLTI7IC8vIGQgaXNuJ3QgaW50ZWdlciBhbmQgbmVlZHMgdG9vIG1hbnkgZnJhY3Rpb25hbCBkaWdpdHMKCiAgcmV0dXJuIC1sc2JQb3M7Cn0KCmNvbnN0IGRvdWJsZSB0ZXN0RGF0YVtdID0KewogIDAsCiAgMSwgLy8gMiBeIDAKICAwLjUsIC8vIDIgXiAtMQogIDAuMjUsIC8vIDIgXiAtMgogIDAuMTI1LAogIDAuMDYyNSwgLy8gLi4uCiAgMC4wMzEyNSwKICAwLjAxNTYyNSwKICAwLjAwNzgxMjUsIC8vIDIgXiAtNwogIDEuMC8yNTYsIC8vIDIgXiAtOAogIDEuMC8yNTYvMjU2LCAvLyAyIF4gLTE2CiAgMS4wLzI1Ni8yNTYvMjU2LCAvLyAyIF4gLTI0CiAgMS4wLzI1Ni8yNTYvMjU2LzI1NiwgLy8gMiBeIC0zMgogIDEuMC8yNTYvMjU2LzI1Ni8yNTYvMjU2LzI1Ni8yNTYvMjU2LCAvLyAyIF4gLTY0CiAgMy4xNDE1OTI2NTM1ODk3OTMyMzg0NjI2NDMzODMyNzk1MDI4ODQxOTcxNjkzOTkzNzUxMDU4MjA5NzQ5NDQ1OSwKICAwLjEsCiAgSU5GSU5JVFksCiNpZmRlZiBOQU4KICBOQU4sCiNlbmRpZgogIERCTF9NSU4KfTsKCmludCBtYWluKHZvaWQpCnsKICB1bnNpZ25lZCBpOwogIGZvciAoaSA9IDA7IGkgPCBzaXplb2YodGVzdERhdGEpIC8gc2l6ZW9mKHRlc3REYXRhWzBdKTsgaSsrKQogIHsKICAgIGludCBkaWdpdHMgPSBGcmFjdGlvbmFsRGlnaXRzKHRlc3REYXRhW2ldKTsKICAgIGFzc2VydChkaWdpdHMgPj0gMCk7CiAgICBwcmludGYoIiVmICVlICUuKmZcbiIsIHRlc3REYXRhW2ldLCB0ZXN0RGF0YVtpXSwgZGlnaXRzLCB0ZXN0RGF0YVtpXSk7CiAgfQogIHJldHVybiAwOwp9Cg==