I'm coding a C function that allows me to transform any float or double into a string containing 32 bits of 0s and 1s (according to IEEE754 standard). I'm not going to make use of printf as the objective is to understand the way it works and be able to store the string.
I took the calculus method from this video: https://www.youtube.com/watch?v=8afbTaA-gOQ. It enabled me to deconstruct the floats into 1 bit for the sign, 8 bits for the exponent and 23 bits for the mantissa.
I'm getting some pretty good results, but my converter is still not accurate, and my mantissa is often wrong in the last bits. The method I use to calculate the mantissa is (where strnew is just a malloc of the appropriate length):
char *ft_double_decimals(double n, int len)
{
char *decimals;
int i;
if (!(decimals = ft_strnew(len)))
return (NULL);
i = 0;
while (i < len)
{
n = n * 2;
decimals[i++] = (n >= 1) ? '1' : '0';
n = n - (int)n;
}
return (decimals);
}
For a float such as 0.1 I get this mantissa: 1001 1001 1001 1001 1001 100 where I should get 1001 1001 1001 1001 1001 101. This is so frustrating! I'm obviously missing something here, and I guess it has something to do with a wrong approximation of the decimals, so if someone knows what method I should use instead of the one I'm using I'll be very grateful!
my mantissa is often wrong in the last bits.
When the conversion is incomplete, results should be rounded. #Eric Postpischil
The below rounds half-way cases away from zero.
char *ft_double_decimals(double n, int len) {
char *decimals;
int i;
if (!(decimals = ft_strnew(len)))
return (NULL);
i = 0;
while (i < len) {
n = n * 2;
decimals[i++] = (n >= 1) ? '1' : '0';
n = n - (int) n;
}
// Add rounding code
if (n >= 0.5) {
int carry = 1;
while (i > 0) {
i--;
int sum = decimals[i] - '0' + carry;
decimals[i] = sum % 2 + '0';
carry = sum / 2;
}
if (i == 0 && carry > 0) {
// Rounding into the "one's" digit"
// TBD code to indicate to the caller that event
}
}
return (decimals);
}
int main(void) {
printf("%s\n", ft_double_decimals(0.1f, 23)); // --> 00011001100110011001101
return 0;
}
A more common rounding: round half-way cases to nearest even.
if (n >= 0.5 && (n > 0.5 || ((i > 0) && decimals[i-1] > '0'))) {
Further, calling code needs to be informed when the rounded result is "1.00000..."
Related
I need to redo printf for a projet, so I actually have a problem with the conversion of float.
I managed to convert almost everything but for the number 1254451555.6
I got an issue: I got 1254451555.59999.
I think it's the calculation to keep the part after the . that doesnt work.
nbr = ((n - nbr) * 100000000);
I tried different things but I haven't managed to fix it yet.
Do you have any idea?
int getlenghtitoa(long long n, int nbase)
{
int i;
i = 0;
while (n >= 0)
{
n /= nbase;
i++;
if (n == 0)
break ;
}
return (i);
}
float ft_nbconv(float n, int i)
{
while (i-- > 0)
n = n *10;
return (n);
}
int ft_power(long long nbr)
{
int i;
i = 1;
while(nbr > 10)
{
i *= 10;
nbr = nbr / 10;
}
return (i);
}
char *ft_conver_f(long double n)
{
char *dest;
int i;
int a;
long long int nbr;
int power;
nbr = (long long) n;
i = getlenghtitoa((long long )n, 10);
if (!(dest = malloc(sizeof(char) * (i + 8))))
return (0);
a = i;
i = 0;
power = ft_power(nbr);
while (a--)
{
dest[i++] = ((nbr / power) % 10) + '0';
if (power != 1)
power /= 10;
}
dest[i++] = '.';
nbr = ((n - nbr) * 100000000);
power = 10000000;
while (a++ < 5)
{
if (a == 5)
if ((((nbr / power)) % 10) >= 5)
{
dest[i++] = ((nbr / power) % 10 + 1) + '0';
break;
}
dest[i++] = ((nbr / power) % 10) + '0';
power /= 10;
}
dest[i] = '\0';
return (dest);
}
Most decimal fractions cannot be represented exactly as binary fractions. A consequence is that, in general, the decimal floating-point numbers you enter are only approximated by the binary floating-point numbers actually stored in the machine.
That's why when implementing a printf, the only way to really be able to convert a floating number to a 2-seperated-by-point integers, is by using the precision factor and rounding manually.
If you are not required to implement the precision, the default is 6.
(Precision is the number of places to print after the dot (and it's rounded)).
And that's what's missing in your implementation.
Let's call the digits before the dot the ipart and the digits after the fpart .
nbr = ((n - nbr) * 100000000);
This should be
nbr = ((n - nbr) * 10000000); // 7 zeros
// nbr is now equal to 5999999
if (nbr % 10 >= 5)
{
nbr = nbr / 10 + 1;
}
else
nbr = nbr / 10;
This way, you get 7 digits after the dot, see if the last one is higher than 5, if it is, you add +1 to nbr (after dividing by 10 to make sure nbr has 6 digits), if it's not, you just divide by 10.
One more note about this rounding method, It will not be able to carry the rounding from the fpart to the ipart .
what if you want to print 3.9999999 ? It should print 4.000000. That means that can't just convert the ipart to a string from the beginning, because sometimes rounding the fpart will add +1 to your ipart
So think about creating a function ltoa for example that takes a long long int and converts it to a string, complete the piece of code about rounding i just gave you to make sure rounding can be carried to the ipart , then convert the whole thing to string using something like
dest = join(ltoa(ipart), ".", ltoa(fpart)).
A couple more notes, your function does not handle negative numbers.
And your int ft_pow can be easily flooded, so consider changing to long long ft_pow
I am trying to code a program that will take a floating point number in base 10 and convert its fractional part in base 2. In the following code, I am intending to call my converting function into a printf, and format the output; the issue I have lies in my fra_binary() where I can't figure out the best way to return an integer made of the result of the conversion at each turn respectively (concatenation). Here is what I have done now (the code is not optimized because I am still working on it) :
#include <stdio.h>
#include <math.h>
int fra_binary(double fract) ;
int main()
{
long double n ;
double fract, deci ;
printf("base 10 :\n") ;
scanf("%Lf", &n) ;
fract = modf(n, &deci) ;
int d = deci ;
printf("base 2: %d.%d\n", d, fra_binary(fract)) ;
return(0) ;
}
int fra_binary(double F)
{
double fl ;
double decimal ;
int array[30] ;
for (int i = 0 ; i < 30 ; i++) {
fl = F * 2 ;
F = modf(fl, &decimal) ;
array[i] = decimal ;
if (F == 0) break ;
}
return array[0] ;
}
Obviously this returns partly the desired output, because I would need the whole array concatenated as one int or char to display the series of 1 and 0s I need. So at each turn, I want to use the decimal part of the number I work on as the binary number to concatenate (1 + 0 = 10 and not 1). How would I go about it?
Hope this makes sense!
return array[0] ; is only the first value of int array[30] set in fra_binary(). Code discards all but the first calculation of the loop for (int i = 0 ; i < 30 ; i++).
convert its fractional part in base 2
OP's loop idea is a good starting point. Yet int array[30] is insufficient to encode the fractional portion of all double into a "binary".
can't figure out the best way to return an integer
Returning an int will be insufficient. Instead consider using a string - or manage an integer array in a likewise fashion.
Use defines from <float.h> to drive the buffer requirements.
#include <stdio.h>
#include <math.h>
#include <float.h>
char *fra_binary(char *dest, double x) {
_Static_assert(FLT_RADIX == 2, "Unexpected FP base");
double deci;
double fract = modf(x, &deci);
fract = fabs(fract);
char *s = dest;
do {
double d;
fract = modf(fract * 2.0, &d);
*s++ = "01"[(int) d];
} while (fract);
*s = '\0';
// For debug
printf("%*.*g --> %.0f and .", DBL_DECIMAL_DIG + 8, DBL_DECIMAL_DIG, x,
deci);
return dest;
}
int main(void) {
// Perhaps 53 - -1021 + 1
char fraction_string[DBL_MANT_DIG - DBL_MIN_EXP + 1];
puts(fra_binary(fraction_string, -0.0));
puts(fra_binary(fraction_string, 1.0));
puts(fra_binary(fraction_string, asin(-1))); // machine pi
puts(fra_binary(fraction_string, -0.1));
puts(fra_binary(fraction_string, DBL_MAX));
puts(fra_binary(fraction_string, DBL_MIN));
puts(fra_binary(fraction_string, DBL_TRUE_MIN));
}
Output
-0 --> -0 and .0
1 --> 1 and .0
3.1415926535897931 --> 3 and .001001000011111101101010100010001000010110100011
-0.10000000000000001 --> -0 and .0001100110011001100110011001100110011001100110011001101
1.7976931348623157e+308 --> 179769313486231570814527423731704356798070600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 and .0
2.2250738585072014e-308 --> 0 and .00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
4.9406564584124654e-324 --> 0 and .000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
Also unclear why input is long double, yet processing is with double. Recommend using just one FP type.
Note that your algorithm finds out the binary representation of the fraction most significant bit first.
One way to convert the fractional part to a binary string, would be to supply the function with a string and a string length, and have the function fill it with up to that many binary digits:
/* This function returns the number of chars needed in dst
to describe the fractional part of value in binary,
not including the trailing NUL ('\0').
Returns zero in case of an error (non-finite value).
*/
size_t fractional_bits(char *dst, size_t len, double value)
{
double fraction, integral;
size_t i = 0;
if (!isfinite(value))
return 0;
if (value > 0.0)
fraction = modf(value, &integral);
else
if (value < 0.0)
fraction = modf(-value, &integral);
else {
/* Zero fraction. */
if (len > 1) {
dst[0] = '0';
dst[1] = '\0';
} else
if (len > 0)
dst[0] = '\0';
/* One binary digit was needed for exact representation. */
return 1;
}
while (fraction > 0.0) {
fraction = fraction * 2.0;
if (fraction >= 1.0) {
fraction = fraction - 1.0;
if (i < len)
dst[i] = '1';
} else
if (i < len)
dst[i] = '0';
i++;
}
if (i < len)
dst[i] = '\0';
else
if (len > 0)
dst[len - 1] = '\0';
return i;
}
The above function works very much like snprintf(), except it takes only the double whose fractional bits are to be stored as a string of binary digits (0 or 1). and returns 0 in case of an error (non-finite double value).
Another option is to use an unsigned integer type to hold the bits. For example, if your code is intended to work on architectures where double is an IEEE-754 Binary64 type or similar, the mantissa has up to 53 bits of precision, and an uint64_t would suffice.
Here is an example of that:
uint64_t fractional_bits(const double val, size_t bits)
{
double fraction, integral;
uint64_t result = 0;
if (bits < 1 || bits > 64) {
errno = EINVAL;
return 0;
}
if (!isfinite(val)) {
errno = EDOM;
return 0;
}
if (val > 0.0)
fraction = modf(val, &integral);
else
if (val < 0.0)
fraction = modf(-val, &integral);
else {
errno = 0;
return 0;
}
while (bits-->0) {
result = result << 1;
fraction = fraction * 2.0;
if (fraction >= 1.0) {
fraction = fraction - 1.0;
result = result + 1;
}
}
errno = 0;
return result;
}
The return value is the binary representation of the fractional part: [i]fractional_part[/i] ≈ [i]result[/i] / 2[sup][i]bits[/i][/sup], where [i]bits[/i] is between 1 and 64, inclusive.
In order for the caller to detect an error, the function clears errno to zero if no error occurred. If an error does occur, the function returns zero with errno set to EDOM if the value is not finite, or to EINVAL if bits is less than 1 or greater than 64.
You can combine the two approaches, if you implement an arbitrary-size unsigned integer type, or a bitmap type.
Suppose I have an array of bytes from a secure PRNG, and I need to generate a number between 1 and 10 using that data, how would I do that correctly?
Think of the array as one big unsigned integer. Then the answer is simple:
(Big_Number % 10) + 1
So all that is needed is a method to find the modulus 10 of big integers. Using modular exponentiation:
#include <limits.h>
#include <stdlib.h>
int ArrayMod10(const unsigned char *a, size_t n) {
int mod10 = 0;
int base = (UCHAR_MAX + 1) % 10;
for (size_t i = n; i-- > 0; ) {
mod10 = (base*mod10 + a[i]) % 10;
base = (base * base) % 10;
}
return mod10;
}
void test10(size_t n) {
unsigned char a[n];
// fill array with your secure PRNG
for (size_t i = 0; i<n; i++) a[i] = rand();
return ArrayMod10(a, n) + 1;
}
There will be a slight bias as 256^n is not a power of 10. With large n, this will rapidly decrease in significance.
Untested code: Detect if a biased result occurred. Calling code could repeatedly call this function with new a array values to get an unbiased result on the rare occasions when bias occurs.
int ArrayMod10BiasDetect(const unsigned char *a, size_t n, bool *biasptr) {
bool bias = true;
int mod10 = 0;
int base = (UCHAR_MAX + 1) % 10; // Note base is usually 6: 256%10, 65536%10, etc.
for (size_t i = n; i-- > 0; ) {
mod10 = (base*mod10 + a[i]) % 10;
if (n > 0) {
if (a[i] < UCHAR_MAX) bias = false;
} else {
if (a[i] < UCHAR_MAX + 1 - base) bias = false;
}
base = (base * base) % 10;
}
*biaseptr = bias;
return mod10;
}
As per the comments follow-up, it seems what you need is modulus operator [%].
You may also need to check the related wiki.
Note: Every time we use the modulo operator on a random number, there is a probability that we'll be running into modulo bias, which ends up in disbalancing the fair distribution of random numbers. You've to take care of that.
For a detailed discussion on this, please see this question and related answers.
It depends on a bunch of things. Secure PRNG sometimes makes long byte arrays instead of integers, let's say it is 16 bytes long array, then extract 32 bit integer like so: buf[0]*0x1000000+buf[1]*0x10000+buf[2]*0x100+buf[3] or use shift operator. This is random so big-endian/little-endian doesn't matter.
char randbytes[16];
//...
const char *p = randbytes;
//assumes size of int is 4
unsigned int rand1 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3]; p += 4;
unsigned int rand2 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3]; p += 4;
unsigned int rand3 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3]; p += 4;
unsigned int rand4 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3];
Then use % on the integer
ps, I think that's a long answer. If you want number between 1 and 10 then just use % on first byte.
OK, so this answer is in Java until I get to my Eclipse C/C++ IDE:
public final static int simpleBound(Random rbg, int n) {
final int BYTE_VALUES = 256;
// sanity check, only return positive numbers
if (n <= 0) {
throw new IllegalArgumentException("Oops");
}
// sanity check: choice of value 0 or 0...
if (n == 1) {
return 0;
}
// sanity check: does not fit in byte
if (n > BYTE_VALUES) {
throw new IllegalArgumentException("Oops");
}
// optimization for n = 2^y
if (Integer.bitCount(n) == 1) {
final int mask = n - 1;
return retrieveRandomByte(rbg) & mask;
}
// you can skip to this if you are sure n = 10
// z is upper bound, and contains floor(z / n) blocks of n values
final int z = (BYTE_VALUES / n) * n;
int x;
do {
x = retrieveRandomByte(rbg);
} while (x >= z);
return x % n;
}
So n is the maximum value in a range [0..n), i.e. n is exclusive. For a range [1..10] simply increase the result with 1.
I would like to produce a function which takes an integer x and char array in, and returns a string x steps into the sequence.
For example, consider the alphabet 'abc', which would produce the strings a, b, c, aa, ab, ac, ba, bb, bc, ca, cb, cc, aaa, aab... If the index 0 was passed in, I would expect the output to be 'a'; likewise, if the index 34 was passed in, I would expect the output 'cbb'.
For the alphabet '0123456789' I would expect the strings 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11...
I have written the following thus far, but am getting stuck on cases 21-23, 33-35, 45-47 where the behaviour deviates and I've been staring at this for a number of hours now without a pattern jumping out at me (with respect to the alphabet size and index). At first I didn't notice the issue, using a larger sized alphabet until it created bigger issues further in my program.
I'm not going to pretend the code below is in anyway elegant, following good practice, nor optimised - at this stage I really just want to understand the correct implementation of this pattern and have been changing things all over the place to attempt to resolve the issue. Apologies in advance if the variable names are confusing. Also, is this a common pattern/issue? I have tried to search for similar algorithms but have been unable to find anything with the terms that come to mind.
unsigned long power(int num, int exp)
{
int i;
unsigned long ret = num;
if (exp == 0) return 1;
for (i = 1; i < exp; i++)
{
ret *= num;
}
return ret;
}
unsigned long sumsqr(int base, int exp)
{
unsigned long sum;
for (sum = 0; exp > 0; exp--)
{
sum += power(base, exp);
}
return sum;
}
char * generateStringT(unsigned long index, char * charmap)
{
unsigned long scaler;
unsigned long remainder;
unsigned long divisor;
int base;
int exponent;
int factor;
char * buffer;
char * string;
int i;
buffer = malloc(sizeof(char) * 100);
i = 0;
base = strlen(charmap);
exponent = 0;
divisor = 0;
remainder = index;
while(sumsqr(base, exponent) <= index)
{
exponent++;
}
exponent--;
factor = exponent;
while(factor >= 0)
{
divisor = power(base, factor);
if ((factor > 1) && (exponent > 0))
divisor += power(base, factor-1);
scaler = remainder/divisor;
remainder = remainder - scaler * divisor;
printf("%lu,", scaler);
if ((factor == exponent) && (exponent > 0)) scaler--;
buffer[i++] = charmap[scaler];
factor--;
}
buffer[i++] = '\0';
string = malloc((strlen(buffer) + 1) * sizeof(char));
strcpy(string, buffer);
free(buffer);
return string;
}
What you are trying to do there looks like a base conversion, but actually is slightly different. Any number in any base can be thought as if they have infinitely many preceding zeros (or whatever the least significant digit is at that base) behind the represented number. This is not true in your case.
In your case, you lay importance to the amount of digits on the number you represent, making it slightly more complicated to index them. With bases in maths, it is easy to calculate the index of a represented number in any base b; that is, sum of the rank times the base raised to the power of order for each digit. In your case, the index builds up an additional sum_{k = 1}^{amount.of.digits.on.our.number - 1} base^k. If we subtract that addition from the index, our task becomes rather easy.
That addition can be calculated using your sumsqr function.
Here, I have changed your code just a little, with comments at where I've done changes, which is able to resolve many, just like you expect it to:
// added this
remainder -= sumsqr(base, exponent);
while (factor >= 0)
{
divisor = power(base, factor);
// commented this out
// if ((factor > 1) && (exponent > 0))
// divisor += power(base, factor - 1);
scaler = remainder/divisor;
remainder = remainder - scaler * divisor;
printf("%lu,", scaler);
// commented this out
// if ((factor == exponent) && (exponent > 0))
// scaler--;
buffer[i++] = charmap[scaler];
factor--;
}
I am not exactly sure what you were trying to do with the parts I've commented out. My guess is that you were trying to increase the divisor by that amount of difference I've talked previously, instead of decreasing the index or remainder by that amount.
Hope this helps in any way.
Not a fix (at a glance, your code uses a similar idea -- but more complicated!), but this is the code I used to convert an integer index to an a,b,c-format page number:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *number_alpha (char *dest, int value, char *base)
{
char *ddest = dest, *startdest = dest, swop;
if (value < 0)
{
value = -value;
*dest = '-';
startdest++;
ddest++;
}
value++;
do
{
*ddest = base[((value-1) % strlen(base))];
ddest++;
value = (value-1)/strlen(base);
} while (value > 0);
*ddest = 0;
ddest--;
while (ddest > startdest)
{
swop = *ddest;
*ddest = *startdest;
*startdest = swop;
startdest++;
ddest--;
}
return dest;
}
int main (int argc, char **argv)
{
int number;
char result[256];
if (argc != 3)
{
printf ("usage: [number] [string]\n");
return -1;
}
number = strtol (argv[1], NULL, 10);
number_alpha (result, number, argv[2]);
printf ("%d in 'base' %s yields %s\n", number, argv[2], result);
return 0;
}
It is very similar to the common task 'convert an integer to decimal notation'. By removing the value++ and changing (value-1) twice to just value in number_alpha, you get a bog-standard Int-To-Ascii routine. This one is special because the "wrap" occurs at a different place: for a base of 0123456789, incrementing 9 shows 00, not 10.
Sample outputs:
0 in 'base' abc yields a
34 in 'base' abc yields cbb
34 in 'base' 0123456789 yields 24
-34 in 'base' abc yields -cbb
9 in 'base' 0123456789 yields 9
10 in 'base' 0123456789 yields 00
--
See Translate a column index into an Excel Column Name for a couple of implementations in other languages. They seem to focus on recursive solutions, where mine is linear (for better or worse).
I'm working on a program that regards with currency. Ive been finding a solution to display money values decently like this:
9,999.99 USD
Remember when assigning a certain variable with a value (money), you musn't insert commas.
I.e.:
double money=9999.99;
And when accessing it;
printf("%.2l USD",money);
Which will output:
9999.99 USD
This is not what I want, especially on bigger amounts exceeding the hundredth, thousandth, millionth, or even billionth place value.
Now I can't find any solution than printing out the desired output directly on the printf.
printf("9,999.99");
Which is undesirable with many variables.
Can anyone help me out?
Please take a look and printf manual page taking note of the following bit:
*"For some numeric conversions a radix character ("decimal point") or thousands' grouping character is used. The actual character used depends on the LC_NUMERIC part of the locale. The POSIX locale uses '.' as radix character, and does not have a grouping character. Thus,
printf("%'.2f", 1234567.89);
results in "1234567.89" in the POSIX locale, in "1234567,89" in the nl_NL locale, and in "1.234.567,89" in the da_DK locale."*
This can be changed by the function setlocale
There is a function, strfmon which might be able to help you
First, don't use floating-point types to represent money because normally floating-point types are binary and as such cannot represent all decimal fractions (cents) exactly, further these types are prone to rounding errors. Use integers instead and count cents instead of dollars.
#include <stdio.h>
#include <limits.h>
unsigned long long ConstructMoney(unsigned long long dollars, unsigned cents)
{
return dollars * 100 + cents;
}
void PrintWithCommas(unsigned long long n)
{
char s[sizeof n * CHAR_BIT + 1];
char *p = s + sizeof s;
unsigned count = 0;
*--p = '\0';
do
{
*--p = '0' + n % 10;
n /= 10;
if (++count == 3 && n)
{
*--p = ',';
count = 0;
}
} while (n);
printf("%s", p);
}
void PrintMoney(unsigned long long n)
{
PrintWithCommas(n / 100);
putchar('.');
n %= 100;
putchar('0' + n / 10);
putchar('0' + n % 10);
}
int main(void)
{
PrintMoney(ConstructMoney(0, 0)); puts("");
PrintMoney(ConstructMoney(0, 1)); puts("");
PrintMoney(ConstructMoney(1, 0)); puts("");
PrintMoney(ConstructMoney(1, 23)); puts("");
PrintMoney(ConstructMoney(12, 34)); puts("");
PrintMoney(ConstructMoney(123, 45)); puts("");
PrintMoney(ConstructMoney(1234, 56)); puts("");
PrintMoney(ConstructMoney(12345, 67)); puts("");
PrintMoney(ConstructMoney(123456, 78)); puts("");
PrintMoney(ConstructMoney(1234567, 89)); puts("");
return 0;
}
Output (ideone):
0.00
0.01
1.00
1.23
12.34
123.45
1,234.56
12,345.67
123,456.78
1,234,567.89
If you're using the standard library, there's no way to do this -- you have to write some code that does it by hand.
I would recommend multiplying the value by 100, casting to integer, and printing the digits with separators as needed -- it's much easier to handle individual digits on an integer.
The following code, for instance, will fill a char * buffer with the string representation of the value you have:
void formatString (double number, char * buffer) {
if (number < 0) {
*buffer = '-';
formatString(number, buffer + 1);
return;
}
unsigned long long num = (unsigned long long) (number * 100);
unsigned long long x; // temporary storage for counting the digits
unsigned char digits;
for (x = num / 1000, digits = 1; x; digits ++, x /= 10);
// counts the digits, also ensures that there's at least one digit
unsigned char pos; // digit position
for (pos = 1, x = 100; pos < digits; pos ++, x *= 10);
// reuses x as a value for extracting the digit in the needed position;
char * current = buffer;
for (pos = digits; pos; pos --) {
*(current ++) = 48 + (num / x);
// remember 48 + digit gives the ASCII for the digit
if (((pos % 3) == 1) && (pos > 1)) *(current ++) = ',';
num %= x;
x /= 10;
}
*(current ++) = '.';
*(current ++) = 48 + num / 10;
*(current ++) = 48 + num % 10;
*current = 0;
}