Reputation: 507
I need to decompose a decimal part of a number in single digits, but I need to get the most obvious representation. Here is my code, to be clearer :
#include <stdio.h>
void main(){
double value = 0.123;
int decim_tab[6];
int decimal;
int i;
for (i = 0; i < 6; ++i) {
value *= 10;
decimal = (int)value;
decim_tab[i] = decimal;
value -= decimal;
}
for (i = 0; i < 6; ++i)
print("%d\n", decim_tab[i]);
}
The output I need is :
1
2
3
0
0
0
But I get :
1
2
2
9
9
9
EDIT
A solution I found is to add a small delta to the value in order to force the shortest representation :
#include <stdio.h>
void main(){
double value = 0.123;
int decim_tab[6];
int decimal;
int i;
value += 0.000000001
for (i = 0; i < 6; ++i) {
value *= 10;
decimal = (int)value;
decim_tab[i] = decimal;
value -= decimal;
}
for (i = 0; i < 6; ++i)
print("%d\n", decim_tab[i]);
}
I would be happy to find a better way, any suggestions ?
Upvotes: 4
Views: 172
Reputation: 99
The reason you get unexpected output is that decimal fractions cannot always be exactly represented using (most common) base two floating point numbers. Using printf("%.20f", value);
after your assignment of value
you will see that the value 0.123 is actually being stored as 0.12299..., which is why you receive that output.
If you only need to print out six digits, you can use string formatting of floating point numbers:
#include <stdio.h>
#include <stdlib.h>
int main(){
double value = 0.123;
char *s = malloc(9);
sprintf(s++, "%.6f", value);
while(*s++){
putchar(*s);
putchar('\n');
}
}
EDIT: The code in my answer is very specific to the example you gave, so when using it be aware that I made some assumptions, e.g. your value will never have more than one digit before the decimal point.
Upvotes: 3
Reputation: 133019
Floating point numbers are not exact value representation. Here's a simple sample:
double a = 0.15 + 0.15; // 0.15 + 0.15 == 0.3, right?
double b = 0.1 + 0.2; // 0.1 + 0.2 == 0.3, right?
if (a == b) {
printf("Equal\n");
} else {
printf("Unequal\n");
}
What will that print? Equal
? Are you sure? Try it yourself:
It prints Unequal
, that's because there are some numbers that floating point can't represent exactly and that's something you always need to keep in mind when doing floating point math. Also there is rounding involved in many operations, so the results of math operations are as good as possible but not always "exact", there's a tiny error that can also sum up if you run multiple operations.
double value = 0.123;
// Assuming none of your numbers has more than 58 digits,
// one period and one termination char.
char buffer[60];
// Print the number to the buffer.
// Missing: Error checking if it did fit!
snprintf(buffer, sizeof(buffer), "%f", value);
// Find the period or end of string
int idx = 0;
for (; buffer[idx] && buffer[idx] != '.'; idx++);
// Print anything after the period till
// the end of the string
if (buffer[idx] == '.') {
for (idx++; buffer[idx]; idx++) {
printf("%c\n", buffer[idx]);
}
}
Test it: http://rextester.com/CYDQO24769
Upvotes: 1
Reputation: 144780
If you want 6 decimal places, you should add 0.0000005
(ie 0.5e-6
) to round the value to the nearest place. This method will work for positive numbers, first extract the sign, then work on the absolute value.
Upvotes: 1