How can I stringify a fraction with N decimals in C++ - c++

I want to stringify a fraction of unsigned integers in C++ with variable precision. So 1/3 would be printed as 0.33 using a precision of 2. I know that float and std::ostream::precision could be used for a quick and dirty solution:
std::string stringifyFraction(unsigned numerator,
unsigned denominator,
unsigned precision)
{
std::stringstream output;
output.precision(precision);
output << static_cast<float>(numerator) / denominator;
return output.str();
}
However, this is not good enough because float has limited precision and can't actually represent decimal numbers accurately. What other options do I have? Even a double would fail if I wanted 100 digits or so, or in case of a recurring fraction.

It's always possible to just perform long division to stringify digit-by-digit. Note that the result consists of an integral part and a fractional part. We can get the integral part by simply dividing using the / operator and calling std::to_string. For the rest, we need the following function:
#include <string>
std::string stringifyFraction(const unsigned num,
const unsigned den,
const unsigned precision)
{
constexpr unsigned base = 10;
// prevent division by zero if necessary
if (den == 0) {
return "inf";
}
// integral part can be computed using regular division
std::string result = std::to_string(num / den);
// perform first step of long division
// also cancel early if there is no fractional part
unsigned tmp = num % den;
if (tmp == 0 || precision == 0) {
return result;
}
// reserve characters to avoid unnecessary re-allocation
result.reserve(result.size() + precision + 1);
// fractional part can be computed using long divison
result += '.';
for (size_t i = 0; i < precision; ++i) {
tmp *= base;
char nextDigit = '0' + static_cast<char>(tmp / den);
result.push_back(nextDigit);
tmp %= den;
}
return result;
}
You could easily extend this to work with other bases as well, by just making base a template parameter, but then you couldn't just use std::to_string anymore.

Related

is it possible to show a fractional number in the output of c++? [duplicate]

In C++, When I calculate 2/3, it will output decimal values, how can I just get the original format (i.e.g 2/3) instead of 0.66666667
Thanks
You can't. You would need to write a class dedicated to holding rational numbers (i.e. fractions). Or maybe just use the Boost Rational Number library.
If I understand correctly, you have a floating point number (a float or double type variable), and you'd like to output this value as a fraction.
If that is the case, you need to further specify your question:
A FP number is a fraction, by definition: A FP number consists of two integers, a mantissa m and an expontent e (and a sign, but that's irrelevant here). So each FP number is really a pair (m,e), and the value f it represents is f=mb^e (where b is a fixed integral base, usually 2). So the natural representation as a fraction is simply m / b^(-e) with e<0 (if e>=0 , f is integral anyway).
However, you probably want to get the fraction with the smallest reasonable divisor. This is a different question. To get is, you could e.g. use the bestappr function from the Pari/GP library. In your case, you'd probably use bestappr(x, A), with x your input, and A the largest denominator you want to try. bestappr will give you the fraction closest to x whose denominator is still smaller than A.
write your own Rational class to calculate divisions
class Rational
{
public:
int numerator, denominator;
Rational(int num, int den=1){
numerator = num;
denominator=den;
}
Rational(Rational other){
numerator = other.numerator;
denominator = other.denominator;
}
double operator / (int divisor){
denominator *= divisor;
simplificate();
return getrealformat();
}
Rational& operator / (int divisor){
denominator *= divisor;
simplificate();
return this;
}
Rational& operator / (Rational &divisor){
numerator *= divisor.numerator;
denominator *= divisor.denominator;
simplificate();
return this;
}
double operator / (int divisor){
denominator *= divisor;
simplificate();
return getrealformat();
}
double getrealformat(){
return numerator/denominator;
}
simplificate(){
int commondivisor = 1;
for(int i=2;i<=min(abs(numerator), abs(denominator));i++)
if( numerator%i == 0 && denominator%i == 0 )
commondivisor = i;
numerator /= commondivisor;
denominator /= commondivisor;
}
};
use
Rational r1(45), r2(90), r3=r1/r2;
cout<<r3.numerator<<'/'<<r3.denominator;
cout<<r3.getrealformat();
how can I just get the original format
(i.e.g 2/3) instead of 0.66666667
Only with great difficulty by wrapping something like the GMP library with custom output operators. Below is a bit more on GMP:
What is GMP?
GMP is a free library for
arbitrary precision arithmetic,
operating on signed integers, rational
numbers, and floating point numbers.
There is no practical limit to the
precision except the ones implied by
the available memory in the machine
GMP runs on. GMP has a rich set of
functions, and the functions have a
regular interface.
The main target applications for GMP
are cryptography applications and
research, Internet security
applications, algebra systems,
computational algebra research, etc.
GMP is carefully designed to be as
fast as possible, both for small
operands and for huge operands. The
speed is achieved by using fullwords
as the basic arithmetic type, by using
fast algorithms, with highly optimised
assembly code for the most common
inner loops for a lot of CPUs, and by
a general emphasis on speed.
GMP is faster than any other bignum
library. The advantage for GMP
increases with the operand sizes for
many operations, since GMP uses
asymptotically faster algorithms.
The first GMP release was made in
1991. It is continually developed and maintained, with a new release about
once a year.
You have to store them in some sort of Fraction class with two integer fields. Of course, you have to simplify the fraction before using it for output.
You can develop your own class or use some libraries, like this one for exact maths: CLN - Class Library for Numbers
This is impossible in general: floating point numbers are not precise and do not retain sufficient information to fully reconstruct a fraction.
You could, however, write a function that heuristically finds an "optimal" approximation, whereby fractions with small numerators and denominators are preferred, as are fractions that have almost the same value as the floating point number.
If you're in full control of the code, Oli's idea is better: don't throw away the information in the first place.
You can store all your fraction's numerators and denominators as intergers. Integers have exact representations in binary.
To simplify efforts, I suggest you stick with known denominators if possible.
I'm working with an application where the fractions are restricted to denominators of powers of 2 or using 3 (for thirds).
I convert to these fractions using an approximation (rounding to the nearest 1.0/24.0).
Without some restrictions, finding the denominator can be quite a chore and take up a lot of the execution time.
I am beginner and this way that I use may not be a proper way
#include <iostream>
using namespace std;
int main ()
{
double a;
double b;
double c;
cout << "first number: ";
cin >> a;
cout << "second number: ";
cin >> b;
c = a/b;
cout << "result is: " << c << endl;
if (b != 0) {
if (a > 0) {
if (c - (int)c > 0 && c - (int)c < 1)
cout << "fraction: " << a << "/" << b;
} else {
if (c - (int)c < 0 && c - (int)c < 1)
cout << "fraction: " << a << "/" << b;
}
}
return 0;
}
Dividing both numbers with their HCF might help.
#include <iostream>
using namespace std;
int main() {
int a,b,q,r;
cin>>a>>b;//first number and second number
q = a/b;
r = a-q*b;
cout<<q<<" "<<r<<" "<<"/"<<" "<<b<<"\n";
return 0;
}
I just got quotient by a/b then got the remainder by a-q*b.
open for suggetions if any.
Use greatest common divisor concept.
if we divide the numbers with gcd of their numbers we get least possible value of those.example:-
#define si long long
int main() {
si int total=4;
si int count=2;
si int g= __gcd(count,total);
count/=g;
total/=g;
cout<<count<<"/"<<total<<endl;
}
for more reference check out this:-https://www.codechef.com/viewsolution/17873537
This is a program to convert a decimal number into a fraction
#include<iostream>
using namespace std;
int main()
{
float num, origNum, rem = 1;
int den = 1, i, count=0, gcd=1;
cout << "Enter any float number to convert it into mixed fraction: ";
cin >> origNum;
num = origNum - static_cast<int>(origNum);
if (num > 0.1)
{
while ( (rem > 0.1) )
{
num = num * 10;
rem = num - static_cast<int>(num);
count++;
}
for (i = 1; i <= count; i++) // counter is for the calculation of denominator part of mixed fraction
{
den = den * 10;
}
for (i = 2; i <= num|| i<=rem; i++)
{
if( (static_cast<int>(num) % i == 0) && (den % i == 0) )
{
gcd = i;
}
}
cout << (static_cast<int>(origNum)) << " and " << (static_cast<int>(num))/gcd << "/" << den/gcd;
}
else
cout << (static_cast<int>(origNum));
return 0;
}

Truncating a double floating point at a certain number of digits

I have written the following routine, which is supposed to truncate a C++ double at the n'th decimal place.
double truncate(double number_val, int n)
{
double factor = 1;
double previous = std::trunc(number_val); // remove integer portion
number_val -= previous;
for (int i = 0; i < n; i++) {
number_val *= 10;
factor *= 10;
}
number_val = std::trunc(number_val);
number_val /= factor;
number_val += previous; // add back integer portion
return number_val;
}
Usually, this works great... but I have found that with some numbers, most notably those that do not seem to have an exact representation within double, have issues.
For example, if the input is 2.0029, and I want to truncate it at the fifth place, internally, the double appears to be stored as something somewhere between 2.0028999999999999996 and 2.0028999999999999999, and truncating this at the fifth decimal place gives 2.00289, which might be right in terms of how the number is being stored, but is going to look like the wrong answer to an end user.
If I were rounding instead of truncating at the fifth decimal, everything would be fine, of course, and if I give a double whose decimal representation has more than n digits past the decimal point it works fine as well, but how do I modify this truncation routine so that inaccuracies due to imprecision in the double type and its decimal representation will not affect the result that the end user sees?
I think I may need some sort of rounding/truncation hybrid to make this work, but I'm not sure how I would write it.
Edit: thanks for the responses so far but perhaps I should clarify that this value is not producing output necessarily but this truncation operation can be part of a chain of many different user specified actions on floating point numbers. Errors that accumulate within the double precision over multiple operations are fine, but no single operation, such as truncation or rounding, should produce a result that differs from its actual ideal value by more than half of an epsilon, where epsilon is the smallest magnitude represented by the double precision with the current exponent. I am currently trying to digest the link provided by iinspectable below on floating point arithmetic to see if it will help me figure out how to do this.
Edit: well the link gave me one idea, which is sort of hacky but it should probably work which is to put a line like number_val += std::numeric_limits<double>::epsilon() right at the top of the function before I start doing anything else with it. Dunno if there is a better way, though.
Edit: I had an idea while I was on the bus today, which I haven't had a chance to thoroughly test yet, but it works by rounding the original number to 16 significant decimal digits, and then truncating that:
double truncate(double number_val, int n)
{
bool negative = false;
if (number_val == 0) {
return 0;
} else if (number_val < 0) {
number_val = -number_val;
negative = true;
}
int pre_digits = std::log10(number_val) + 1;
if (pre_digits < 17) {
int post_digits = 17 - pre_digits;
double factor = std::pow(10, post_digits);
number_val = std::round(number_val * factor) / factor;
factor = std::pow(10, n);
number_val = std::trunc(number_val * factor) / factor;
} else {
number_val = std::round(number_val);
}
if (negative) {
number_val = -number_val;
}
return number_val;
}
Since a double precision floating point number only can have about 16 digits of precision anyways, this just might work for all practical purposes, at a cost of at most only one digit of precision that the double would otherwise perhaps support.
I would like to further note that this question differs from the suggested duplicate above in that a) this is using C++, and not Java... I don't have a DecimalFormatter convenience class, and b) I am wanting to truncate, not round, the number at the given digit (within the precision limits otherwise allowed by the double datatype), and c) as I have stated before, the result of this function is not supposed to be a printable string... it is supposed to be a native floating point number that the end user of this function might choose to further manipulate. Accumulated errors over multiple operations due to imprecision in the double type are acceptable, but any single operation should appear to perform correctly to the limits of the precision of the double datatype.
OK, if I understand this right, you've got a floating point number and you want to truncate it to n digits:
10.099999
^^ n = 2
becomes
10.09
^^
But your function is truncating the number to an approximately close value:
10.08999999
^^
Which is then displayed as 10.08?
How about you keep your truncate formula, which does truncate as well as it can, and use std::setprecision and std::fixed to round the truncated value to the required number of decimal places? (Assuming it is std::cout you're using for output?)
#include <iostream>
#include <iomanip>
using std::cout;
using std::setprecision;
using std::fixed;
using std::endl;
int main() {
double foo = 10.08995; // let's imagine this is the output of `truncate`
cout << foo << endl; // displays 10.0899
cout << setprecision(2) << fixed << foo << endl; // rounds to 10.09
}
I've set up a demo on wandbox for this.
I've looked into this. It's hard because you have inaccuracies due to the floating point representation, then further inaccuracies due to the decimal. 0.1 cannot be represented exactly in binary floating point. However you can use the built-in function sprintf with a %g argument that should round accurately for you.
char out[64];
double x = 0.11111111;
int n = 3;
double xrounded;
sprintf(out, "%.*g", n, x);
xrounded = strtod(out, 0);
Get double as a string
If you are looking just to print the output, then it is very easy and straightforward using stringstream:
#include <cmath>
#include <iostream>
#include <iomanip>
#include <limits>
#include <sstream>
using namespace std;
string truncateAsString(double n, int precision) {
stringstream ss;
double remainder = static_cast<double>((int)floor((n - floor(n)) * precision) % precision);
ss << setprecision(numeric_limits<double> ::max_digits10 + __builtin_ctz(precision))<< floor(n);
if (remainder)
ss << "." << remainder;
cout << ss.str() << endl;
return ss.str();
}
int main(void) {
double a = 9636346.59235;
int precision = 1000; // as many digits as you add zeroes. 3 zeroes means precision of 3.
string s = truncateAsString(a, precision);
return 0;
}
Getting the divided floating point with an exact value
Maybe you are looking for true value for your floating point, you can use boost multiprecision library
The Boost.Multiprecision library can be used for computations requiring precision exceeding that of standard built-in types such as float, double and long double. For extended-precision calculations, Boost.Multiprecision supplies a template data type called cpp_dec_float. The number of decimal digits of precision is fixed at compile-time via template parameter.
Demonstration
#include <boost/math/constants/constants.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
#include <limits>
#include <cmath>
#include <iomanip>
using boost::multiprecision::cpp_dec_float_50;
cpp_dec_float_50 truncate(cpp_dec_float_50 n, int precision) {
cpp_dec_float_50 remainder = static_cast<cpp_dec_float_50>((int)floor((n - floor(n)) * precision) % precision) / static_cast<cpp_dec_float_50>(precision);
return floor(n) + remainder;
}
int main(void) {
int precision = 100000; // as many digits as you add zeroes. 5 zeroes means precision of 5.
cpp_dec_float_50 n = 9636346.59235789;
n = truncate(n, precision); // first part is remainder, floor(n) is int value truncated.
cout << setprecision(numeric_limits<cpp_dec_float_50> ::max_digits10 + __builtin_ctz(precision)) << n << endl; // __builtin_ctz(precision) will equal the number of trailing 0, exactly the precision we need!
return 0;
}
Output:
9636346.59235
NB: Requires sudo apt-get install libboost-all-dev

Division of a big number of 100 digits stored as string

I have a 100 digit number stored as string. I want to divide this number with an integer less than 10. How do I efficiently divide a big integer stored as a string with an integer?
You can check the big integer library.
You can use this library in a C++ program to do arithmetic on integers of size limited only by your computer's memory. The library provides BigUnsigned and BigInteger classes that represent nonnegative integers and signed integers, respectively. Most of the C++ arithmetic operators are overloaded for these classes, so big-integer calculations are as easy as:
#include "BigIntegerLibrary.hh"
BigInteger a = 65536;
cout << (a * a * a * a * a * a * a * a);
(prints 340282366920938463463374607431768211456)
Also check GMP
#WasimThabraze - what is your understanding of the longhand division method? Since the divisor is less than 1/2 the size of an integer you can use something like this for each divide:
char array[10] = {9,8,7,6,5,4,3,2,1,0};
void divide(int dvsr)
{
int rem = 0;
int dvnd;
int quot;
int i;
for(i = 0; i < (sizeof(array)/sizeof(array[0])) ; i++){
dvnd = (rem * 10) + array[i];
rem = dvnd % dvsr;
quot = dvnd / dvsr;
array[i] = quot;
}
}
int main(void)
{
divide(8);
return (0);
}
I hope this helps you because not all online judges allow BigIntegerLibrary.I have assumed for some arbitrary input.
string input="123456789";
int n=input.size();
string final(n,'0');
string::const_iterator p=input.begin(),q=input.end();
string::iterator f=final.begin();
void divide(int divisor)
{
int reminder = 0,dividend,quotient;
/*repeatedly divide each element*/
for(; p!=q ; p++,f++){
dividend = (reminder * 10) + (*p-'0');
reminder = dividend % divisor;
quotient = dividend / divisor;
*f = quotient + '0';
}
/*remove any leading zeroes from the result*/
n = final.find_first_not_of("0");
if (n != string::npos)
{
final = final.substr(n);
}
std::cout << final ;
}
int main(){
int x;
std::cin >> x;
divide(x);
return 0;
}

How to output fraction instead of decimal number?

In C++, When I calculate 2/3, it will output decimal values, how can I just get the original format (i.e.g 2/3) instead of 0.66666667
Thanks
You can't. You would need to write a class dedicated to holding rational numbers (i.e. fractions). Or maybe just use the Boost Rational Number library.
If I understand correctly, you have a floating point number (a float or double type variable), and you'd like to output this value as a fraction.
If that is the case, you need to further specify your question:
A FP number is a fraction, by definition: A FP number consists of two integers, a mantissa m and an expontent e (and a sign, but that's irrelevant here). So each FP number is really a pair (m,e), and the value f it represents is f=mb^e (where b is a fixed integral base, usually 2). So the natural representation as a fraction is simply m / b^(-e) with e<0 (if e>=0 , f is integral anyway).
However, you probably want to get the fraction with the smallest reasonable divisor. This is a different question. To get is, you could e.g. use the bestappr function from the Pari/GP library. In your case, you'd probably use bestappr(x, A), with x your input, and A the largest denominator you want to try. bestappr will give you the fraction closest to x whose denominator is still smaller than A.
write your own Rational class to calculate divisions
class Rational
{
public:
int numerator, denominator;
Rational(int num, int den=1){
numerator = num;
denominator=den;
}
Rational(Rational other){
numerator = other.numerator;
denominator = other.denominator;
}
double operator / (int divisor){
denominator *= divisor;
simplificate();
return getrealformat();
}
Rational& operator / (int divisor){
denominator *= divisor;
simplificate();
return this;
}
Rational& operator / (Rational &divisor){
numerator *= divisor.numerator;
denominator *= divisor.denominator;
simplificate();
return this;
}
double operator / (int divisor){
denominator *= divisor;
simplificate();
return getrealformat();
}
double getrealformat(){
return numerator/denominator;
}
simplificate(){
int commondivisor = 1;
for(int i=2;i<=min(abs(numerator), abs(denominator));i++)
if( numerator%i == 0 && denominator%i == 0 )
commondivisor = i;
numerator /= commondivisor;
denominator /= commondivisor;
}
};
use
Rational r1(45), r2(90), r3=r1/r2;
cout<<r3.numerator<<'/'<<r3.denominator;
cout<<r3.getrealformat();
how can I just get the original format
(i.e.g 2/3) instead of 0.66666667
Only with great difficulty by wrapping something like the GMP library with custom output operators. Below is a bit more on GMP:
What is GMP?
GMP is a free library for
arbitrary precision arithmetic,
operating on signed integers, rational
numbers, and floating point numbers.
There is no practical limit to the
precision except the ones implied by
the available memory in the machine
GMP runs on. GMP has a rich set of
functions, and the functions have a
regular interface.
The main target applications for GMP
are cryptography applications and
research, Internet security
applications, algebra systems,
computational algebra research, etc.
GMP is carefully designed to be as
fast as possible, both for small
operands and for huge operands. The
speed is achieved by using fullwords
as the basic arithmetic type, by using
fast algorithms, with highly optimised
assembly code for the most common
inner loops for a lot of CPUs, and by
a general emphasis on speed.
GMP is faster than any other bignum
library. The advantage for GMP
increases with the operand sizes for
many operations, since GMP uses
asymptotically faster algorithms.
The first GMP release was made in
1991. It is continually developed and maintained, with a new release about
once a year.
You have to store them in some sort of Fraction class with two integer fields. Of course, you have to simplify the fraction before using it for output.
You can develop your own class or use some libraries, like this one for exact maths: CLN - Class Library for Numbers
This is impossible in general: floating point numbers are not precise and do not retain sufficient information to fully reconstruct a fraction.
You could, however, write a function that heuristically finds an "optimal" approximation, whereby fractions with small numerators and denominators are preferred, as are fractions that have almost the same value as the floating point number.
If you're in full control of the code, Oli's idea is better: don't throw away the information in the first place.
You can store all your fraction's numerators and denominators as intergers. Integers have exact representations in binary.
To simplify efforts, I suggest you stick with known denominators if possible.
I'm working with an application where the fractions are restricted to denominators of powers of 2 or using 3 (for thirds).
I convert to these fractions using an approximation (rounding to the nearest 1.0/24.0).
Without some restrictions, finding the denominator can be quite a chore and take up a lot of the execution time.
I am beginner and this way that I use may not be a proper way
#include <iostream>
using namespace std;
int main ()
{
double a;
double b;
double c;
cout << "first number: ";
cin >> a;
cout << "second number: ";
cin >> b;
c = a/b;
cout << "result is: " << c << endl;
if (b != 0) {
if (a > 0) {
if (c - (int)c > 0 && c - (int)c < 1)
cout << "fraction: " << a << "/" << b;
} else {
if (c - (int)c < 0 && c - (int)c < 1)
cout << "fraction: " << a << "/" << b;
}
}
return 0;
}
Dividing both numbers with their HCF might help.
#include <iostream>
using namespace std;
int main() {
int a,b,q,r;
cin>>a>>b;//first number and second number
q = a/b;
r = a-q*b;
cout<<q<<" "<<r<<" "<<"/"<<" "<<b<<"\n";
return 0;
}
I just got quotient by a/b then got the remainder by a-q*b.
open for suggetions if any.
Use greatest common divisor concept.
if we divide the numbers with gcd of their numbers we get least possible value of those.example:-
#define si long long
int main() {
si int total=4;
si int count=2;
si int g= __gcd(count,total);
count/=g;
total/=g;
cout<<count<<"/"<<total<<endl;
}
for more reference check out this:-https://www.codechef.com/viewsolution/17873537
This is a program to convert a decimal number into a fraction
#include<iostream>
using namespace std;
int main()
{
float num, origNum, rem = 1;
int den = 1, i, count=0, gcd=1;
cout << "Enter any float number to convert it into mixed fraction: ";
cin >> origNum;
num = origNum - static_cast<int>(origNum);
if (num > 0.1)
{
while ( (rem > 0.1) )
{
num = num * 10;
rem = num - static_cast<int>(num);
count++;
}
for (i = 1; i <= count; i++) // counter is for the calculation of denominator part of mixed fraction
{
den = den * 10;
}
for (i = 2; i <= num|| i<=rem; i++)
{
if( (static_cast<int>(num) % i == 0) && (den % i == 0) )
{
gcd = i;
}
}
cout << (static_cast<int>(origNum)) << " and " << (static_cast<int>(num))/gcd << "/" << den/gcd;
}
else
cout << (static_cast<int>(origNum));
return 0;
}

Printing Hex Floating Point Constants from Array of Bytes

How can a hexadecimal floating point constant, as specified in C99, be printed from a array of bytes representing the machine representation of a floating point value? e.g. given
union u_double
{
double dbl;
char data[sizeof(double)];
};
An example hexadecimal floating point constant is a string of the form
0x1.FFFFFEp127f
A syntax specification for this form of literal can be found on the IBM site, and a brief description of the syntax is here on the GCC site.
The printf function can be used to do this on platforms with access to C99 features in the standard library, but I would like to be able to perform the printing in MSVC, which does not support C99, using standard C89 or C++98.
printf manual says:
a,A
(C99; not in SUSv2) For a conversion, the double argument is converted to hexadecimal notation (using the letters abcdef) in the style [-]0xh.hhhhp�d; for A conversion the prefix 0X, the letters ABCDEF, and the exponent separator P is used. There is one hexadecimal digit before the decimal point, and the number of digits after it is equal to the precision. The default precision suffices for an exact representation of the value if an exact representation in base 2 exists and otherwise is sufficiently large to distinguish values of type double. The digit before the decimal point is unspecified for non-normalized numbers, and non-zero but otherwise unspecified for normalized numbers.
You can use frexp() which is in math.h since at least C90 and then do the conversion yourself. Something like this (not tested, not designed to handle boundaries like NaN, infinities, buffer limits, and so on)
void hexfloat(double d, char* ptr)
{
double fract;
int exp = 0;
if (d < 0) {
*ptr++ = '-';
d = -d;
}
fract = frexp(d, &exp);
if (fract == 0.0) {
strcpy(ptr, "0x0.0");
} else {
fract *= 2.0;
--exp;
*ptr++ = '0';
*ptr++ = 'x';
*ptr++ = '1';
fract -= 1.0;
fract *= 16.0;
*ptr++ = '.';
do {
char const hexdigits[] = "0123456789ABCDEF";
*ptr++ = hexdigits[(int)fract]; // truncate
fract -= (int)fract;
fract *= 16;
} while (fract != 0.0);
if (exp != 0) {
sprintf(ptr, "p%d", exp);
} else {
*ptr++ = '\0';
}
}
}
#include <stdint.h>
#include <stdio.h>
int main(void)
{
union { double d; uint64_t u; } value;
value.d = -1.234e-5;
// see http://en.wikipedia.org/wiki/Double_precision
_Bool sign_bit = value.u >> 63;
uint16_t exp_bits = (value.u >> 52) & 0x7FF;
uint64_t frac_bits = value.u & 0xFFFFFFFFFFFFFull;
if(exp_bits == 0)
{
if(frac_bits == 0)
printf("%s0x0p+0\n", sign_bit ? "-" : "");
else puts("subnormal, too lazy to parse");
}
else if(exp_bits == 0x7FF)
puts("infinity or nan, too lazy to parse");
else printf("%s0x1.%llxp%+i\n",
sign_bit ? "-" : "",
(unsigned long long)frac_bits,
(int)exp_bits - 1023);
// check against libc implementation
printf("%a\n", value.d);
}
This might be an "outside the box" answer, but why not convert the double to a string using sprintf, then parse the string for the mantissa and exponent, convert those to
e.g., something like:
char str[256];
long long a, b, c;
sprintf(str, "%e", dbl);
sscanf(str, "%d.%de%d", &a, &b, &c);
printf("0x%x.%xp%x", a, b, c);
I'm sure you'd have to modify the formats for sprintf and sscanf. And you'd never get a first hex digit between A and F. But in general, I think this idea should work. And it's simple.
A better way would be to find an open source library that implements this format for printf (e.g., newlib, uClibc?) and copy what they do.