Why do I get different results only 1% of the time? - c

I am trying to truncate everything past the hundredths decimal. (13.4396 would be 13.43) Sholdn't it always or never work?
I have this formula that works 99%:
input = (( (double) ((int)(orgInput * 100)) ) / 100) ;
Then I have this formula sequence that is arithmetically equivalent:
input = (orgInput * 100);
input = (int) input;
input = (double) (input);
input = input / 100;
These inputs do not give the desired result (Formula truncates and round down, while the broken down steps output the desired result):
12.33
99.99
22.22
44.32
56.78
11.11
And then an even bigger mystery to me is why 33.30 does not work on either of them. Below is my program that runs continuously to demonstrate my problem.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
double orgInput, input;
while (4!=3)
{
printf("Please enter the dollar amount (up to $100) => ");
scanf("%lf", &orgInput);
/* Truncates anything past hundredths place */
input = (orgInput * 100) ;
printf("\n1. input is %g \n ", input);
input = (int) input ;
printf("\n2. input is %g \n ", input);
input = (double) (input) ;
printf("\n3. input is %g \n", input);
input = input / 100 ;
printf("\n4. input is %.2lf \n", input);
input = (( (double) ((int)(orgInput * 100)) ) / 100) ;
printf("\nUsing the formula the input is %.2lf \n \n\n", input);
}
system("PAUSE");
return 0;
}
Thank you in advance!!!! P.S. Sorry for the formatting I am still getting used to stackoverflow
Key phrases:
Double to int conversion
Precision error

I think you are suffering from floating-point precision errors.
You should be able to fix this by doing:
const double epsilon = 1e-10; // Or some suitable small number
input = floor(orgInput * 100 + epsilon) / 100;
An alternative is to stop this from happening on input. Instead of reading in a double, you read a string and then parse that to get out the dollar and cents amount (cents being exactly 2 digits following the decimal point, if any). You can then ignore everything else.
In general, if you are working with money truncated to cents, you might be best to keep it in cents and use integers. Either that or round instead of truncate (for my above example, that would mean an epsilon of 0.5).

You need to understand that floats are represented in binary as:
2^(exponent) * mantissa
Exponent is a standard integer, but mantissa (a value between 1 and 2) is a number of bits where each bit represents a fraction: 1, 1/2, 1/4, 1/8, 1/16 and so on... Therefore it is not possible for the mantissa to represent certain values exactly, it will have an accuracy of +/- some fraction.
For example you mentioned 33.30. As a float 33.30 can only be: 2^5 * mantissa.
In this case the mantissa has to be 33.30/32 = 1.40625 exactly. But by making it out of the fractions the closest it can be is be is: 1.0406249999999999111821580299874767661094. So the actual value of the double is not 33.30, its 33.2999999999999971578290569595992565155029296875, which of course rounds DOWN to 33.29 when you do the type cast to integer.
The correct way to fix your program is not to scan in a float in the first place. You should be scanning in two integers seperated by decimal, and if scanf returns a value that indicates it did not scan two integers, then scan it as one integer for the case of a dollar only value.
Sadly, printf works by conversions to ints inside it and will not properly print any double precision floats that have more than 6 decimal places, which is why you see it as 33.30 even through you are asking printf to print the value of a double.

Most machines use binary, not decimal floating point. While binary-to-decimal conversion always gives exact values (in theory), it's impossible to convert from decimal to binary without rounding (I'm not considering the impractical case when numbers can have infinite number of digits).
As such, all your binary floating-point numbers are going to be slightly off of what they would've been in decimal.
The only 1-digit decimal fractions that can be represented in binary are: .0, .5.
Likewise, 2-digit decimal fractions exactly representable in binary are: .00, .25, .50, .75 (see here).
If you want, which I doubt, you can round to the nearest fraction of the four.

Related

Determining the number of decimal digits in a floating number

I am trying to write a program that outputs the number of the digits in the decimal portion of a given number (0.128).
I made the following program:
#include <stdio.h>
#include <math.h>
int main(){
float result = 0;
int count = 0;
int exp = 0;
for(exp = 0; int(1+result) % 10 != 0; exp++)
{
result = 0.128 * pow(10, exp);
count++;
}
printf("%d \n", count);
printf("%f \n", result);
return 0;
}
What I had in mind was that exp keeps being incremented until int(1+result) % 10 outputs 0. So for example when result = 0.128 * pow(10,4) = 1280, result mod 10 (int(1+result) % 10) will output 0 and the loop will stop.
I know that on a bigger scale this method is still inefficient since if result was a given input like 1.1208 the program would basically stop at one digit short of the desired value; however, I am trying to first find out the reason why I'm facing the current issue.
My Issue: The loop won't just stop at 1280; it keeps looping until its value reaches 128000000.000000.
Here is the output when I run the program:
10
128000000.000000
Apologies if my description is vague, any given help is very much appreciated.
I am trying to write a program that outputs the number of the digits in the decimal portion of a given number (0.128).
This task is basically impossible, because on a conventional (binary) machine the goal is not meaningful.
If I write
float f = 0.128;
printf("%f\n", f);
I see
0.128000
and I might conclude that 0.128 has three digits. (Never mind about the three 0's.)
But if I then write
printf("%.15f\n", f);
I see
0.128000006079674
Wait a minute! What's going on? Now how many digits does it have?
It's customary to say that floating-point numbers are "not accurate" or that they suffer from "roundoff error". But in fact, floating-point numbers are, in their own way, perfectly accurate — it's just that they're accurate in base two, not the base 10 we're used to thinking about.
The surprising fact is that most decimal (base 10) fractions do not exist as finite binary fractions. This is similar to the way that the number 1/3 does not even exist as a finite decimal fraction. You can approximate 1/3 as 0.333 or 0.3333333333 or 0.33333333333333333333, but without an infinite number of 3's it's only an approximation. Similarly, you can approximate 1/10 in base 2 as 0b0.00011 or 0b0.000110011 or 0b0.000110011001100110011001100110011, but without an infinite number of 0011's it, too, is only an approximation. (That last rendition, with 33 bits past the binary point, works out to about 0.0999999999767.)
And it's the same with most decimal fractions you can think of, including 0.128. So when I wrote
float f = 0.128;
what I actually got in f was the binary number 0b0.00100000110001001001101111, which in decimal is exactly 0.12800000607967376708984375.
Once a number has been stored as a float (or a double, for that matter) it is what it is: there is no way to rediscover that it was initially initialized from a "nice, round" decimal fraction like 0.128. And if you try to "count the number of decimal digits", and if your code does a really precise job, you're liable to get an answer of 26 (that is, corresponding to the digits "12800000607967376708984375"), not 3.
P.S. If you were working with computer hardware that implemented decimal floating point, this problem's goal would be meaningful, possible, and tractable. And implementations of decimal floating point do exist. But the ordinary float and double values any of is likely to use on any of today's common, mass-market computers are invariably going to be binary (specifically, conforming to IEEE-754).
P.P.S. Above I wrote, "what I actually got in f was the binary number 0b0.00100000110001001001101111". And if you count the number of significant bits there — 100000110001001001101111 — you get 24, which is no coincidence at all. You can read at single precision floating-point format that the significand portion of a float has 24 bits (with 23 explicitly stored), and here, you're seeing that in action.
float vs. code
A binary float cannot encode 0.128 exactly as it is not a dyadic rational.
Instead, it takes on a nearby value: 0.12800000607967376708984375. 26 digits.
Rounding errors
OP's approach incurs rounding errors in result = 0.128 * pow(10, exp);.
Extended math needed
The goal is difficult. Example: FLT_TRUE_MIN takes about 149 digits.
We could use double or long double to get us somewhat there.
Simply multiply the fraction by 10.0 in each step.
d *= 10.0; still incurs rounding errors, but less so than OP's approach.
#include <stdio.h>
#include <math.h> int main(){
int count = 0;
float f = 0.128f;
double d = f - trunc(f);
printf("%.30f\n", d);
while (d) {
d *= 10.0;
double ipart = trunc(d);
printf("%.0f", ipart);
d -= ipart;
count++;
}
printf("\n");
printf("%d \n", count);
return 0;
}
Output
0.128000006079673767089843750000
12800000607967376708984375
26
Usefulness
Typically, past FLT_DECMAL_DIG (9) or so significant decimal places, OP’s goal is usually not that useful.
As others have said, the number of decimal digits is meaningless when using binary floating-point.
But you also have a flawed termination condition. The loop test is (int)(1+result) % 10 != 0 meaning that it will stop whenever we reach an integer whose last digit is 9.
That means that 0.9, 0.99 and 0.9999 all give a result of 2.
We also lose precision by truncating the double value we start with by storing into a float.
The most useful thing we could do is terminate when the remaining fractional part is less than the precision of the type used.
Suggested working code:
#include <math.h>
#include <float.h>
#include <stdio.h>
int main(void)
{
double val = 0.128;
double prec = DBL_EPSILON;
double result;
int count = 0;
while (fabs(modf(val, &result)) > prec) {
++count;
val *= 10;
prec *= 10;
}
printf("%d digit(s): %0*.0f\n", count, count, result);
}
Results:
3 digit(s): 128

How to convert float number to string without losing user-entered precision in C?

Here's what I'm trying to do:
I need to print the fractional part of a floating number which has to be input as a float during user input.
The fractional part should be like: if float is 43.3423, the output should be 3423; and if number is 45.3400 output should be 3400.
This can be done easily with a string input but I need a way to make this work with float without losing the extra zeros or without appending zeros to user's original input.
Here's what I already tried :-
Take the fractional part by frac = num - (int)num and then multiplying frac until we get zero as the remainder. But this fails for cases like 34.3400 — the last two zeros won't get included with this method.
Convert the float number to a string by
char string[20];
sprintf(string, "%f", float_number);
The sprintf function puts the float number as a string but here also it doesn't automatically detect the user entered precision and fills the string with extra zeros at the end (6 total precision). So here also the information about the user's original entered precision is not obtained.
So, is there a way to get this done? The number must be taken as float number from user. Is there any way to get info about what's the user's entered precision? If it's not possible, an explanation would be very helpful.
I think I understand where you're coming from. E.g. in physics, it's a difference whether you write 42.5 or 42.500, the number of significant digits is implicitly given. 42.5 stands for any number x: 42.45 <= x < 42.55 and 42.500 for any x: 42.4995 <= x < 42.5005.
For larger numbers, you would use scientific notation: 1.0e6 would mean a number x with x: 950000 <= x < 1050000.
A floating point number uses this same format, but with binary digits (sometimes called bits ;)) instead of decimal digits. But there are two important differences:
The number of digits (bits) used depends only on the data type of the floating point number. If your data type has e.g. 20 bits for the mantissa, every number stored in it will have these 20 bits. The mantissa is always stored without a part after the "decimal" (binary?) point, so you won't know how many significant bits there are.
There's no direct mapping between bits and decimal digits. You will need roughly 3.5 bits to represent a decimal digit. So even if you knew a number of significant bits, you still wouldn't know how many significant decimal digits that would make.
To address your problem, you could store the number of significant digits yourself in something like this:
struct myNumber
{
double value;
int nsignificant;
};
Of course, you have to parse the input yourself to find out what to place in nsignificant. Also, use at least double here for the value, the very limited precision of float won't get you far. With this, you could use nsignificant to determine a proper format string for printing the number with the amount of digits you want.
This still has the problem mentioned above: you can't directly map decimal digits to bits, so there's never a guarantee your number can be stored with the precision you intend. In cases where an exact decimal representation is important, you'll want to use a different data type for that. C# provides one, but C doesn't. You'd have to implement it yourself. You could start with something like this:
struct myDecimal
{
long mantissa;
short exponent;
short nsignificant;
}
In this struct, you could e.g. place 1.0e6 like this:
struct myDecimal x = {
.mantissa = 1;
.exponent = 6;
.nsignificant = 2;
};
Of course, this would require you to write quite a lot of own code for parsing and formatting these numbers.
which has to be input as a float during user input.
So, is there a way to get this done.
Almost. The "trick" is to note the textual length of user input. The below will remember the offset of the first non-whitespace character and the offset after the numeric input.
scanf(" %n%f%n", &n1, &input, &n2);
n2 - n1 gives code the length of user input to represent the float. This method can get fooled if user input is in exponential notation, hexadecimal FP notation, infinity, Not-a-number, excessive leading zeros, etc. Yet works well with straight decimal input.
The idea is to print the number to a buffer with at least n2 - n1 precision and then determine how much of the fractional portion to print.
Recall that float typically has about 6-7 significant leading digits of significance, so attempting to input text like "123456789.0" will result in a float with the exact value of 123456792.0 and the output will be based on that value.
#include <float.h>
#include <math.h>
int scan_print_float(void) {
float input;
int n1, n2;
int cnt = scanf(" %n%f%n", &n1, &input, &n2);
if (cnt == 1) {
int len = n2 - n1;
char buf[len * 2 + 1];
snprintf(buf, sizeof buf, "%.*f", len, input);
char dp = '.';
char *p = strchr(buf, dp);
if (p) {
int front_to_dp = p + 1 - buf;
int prec = len - front_to_dp;
if (prec >= 0) {
return printf("<%.*s>\n", prec, p+1);
}
}
}
puts(".");
return 0;
}
int main(void) {
while (scan_print_float()) {
fflush(stdout);
}
return EXIT_SUCCESS;
}
Input/Output
43.3423
<3423>
45.3400
<3400>
-45.3400
<3400>
0.00
<00>
1234.500000
<500000>
.
.
To robustly handle this and the various edge cases, code should read user input as text and not as a float.
Note: float can typically represent about 232 numbers exactly.
43.3423 is usually not one of them. Instead it has an exactly value of 43.3423004150390625
43.3400 is usually not one of them. Instead it has an exactly value of 43.340000152587890625
The only way is to create a struct with the original string value and/ or required precision for rounding

Save float result number to third digit, no rounding in C

How to round result to third digit after the third digit.
float result = cos(number);
Note that I want to save the result up to the third digit, no rounding. And no, I don't want to print it with .3f, I need to save it as new value;
Example:
0.00367 -> 0.003
N.B. No extra zeroes after 3 are wanted.
Also, I need to be able to get the 3rd digit. For example if it is 0.0037212, I want to get the 3 and use it as an int in some calculation.
0.00367 -> 0.003
A float can typically represent about 232 different values exactly. 0.00367 and 0.003 are not in that set.
The closest float to 0.00367 is 0.0036700000055134296417236328125
The closest float to 0.003__ is 0.0030000000260770320892333984375
I want to save the result up to the third digit
This goal needs a compromise. Save the result to a float near a multiple of 0.001.
Scaling by 1000.0, truncating and dividing by 1000.0 will work for most values.
float y1 = truncf(x * 1000.0f) / 1000.0f;
The above gives a slightly wrong answer with some values near x.xxx000... and x.xxx999.... Using higher precision can solve that.
float y2 = (float) (trunc(x * 1000.0) / 1000.0);
I want to get the 3 and use it as an int in some calculation.
Skip the un-scaling part and only keep 1 digit with fmod().
int digit = (int) fmod((trunc(x * 1000.0), 10);
digit = abs(digit);
In the end, I suspect this approach will not completely satisfy OP's unstated "use it as an int in some calculation.". There are many subtitles to FP math, especially when trying to use a binary FP, as are most double, in some sort of decimal way.
Perhaps the following will meet OP's goal, even though it does some rounding.:
int third_digit = (int) lround(cos(number)*1000.0) % 10;
third_digit = abs(third_digit);
You can scale the value up, use trunc to truncate toward zero, then scale down:
float result = trunc(cos(number) * 1000) / 1000;
Note that due to the inexact nature of floating point numbers, the result won't be the exact value.
If you're looking to specifically extract the third decimal digit, you can do that as follows:
int digit = (int)(result * 1000) % 10;
This will scale the number up so that the digit in question is to the left of the decimal point, then extract that digit.
You can subtract from the number it's remainder from division by 0.001:
result -= fmod(result, 0.001);
Demo
Update:
The question is updated with very conflicting requirements. If you have an exact 0.003 number, there will be infinite numbers of zeroes after it, and it is a mathematical property of numbers. OTOH, float representation cannot guarantee that every exact number of 3 decimal digits will be represented exactly. To solve this problem you will need to give up on using the float type and switch to a some sort of fixed point representation.
Overkill, using sprintf()
double /* or float */ val = 0.00385475337;
if (val < 0) exit(EXIT_FAILURE);
if (val >= 1) exit(EXIT_FAILURE);
char tmp[55];
sprintf(tmp, "%.50f", val);
int third_digit = tmp[4] - '0';

How to determine the number of decimal places in a number?

I am writing a program in C.
Is there any way of determining the number of decimal places
in a float number (i.e. 0.123 = 3, 0.123456 = 6 etc.)?
Other than converting the number to a string and using string
functions to pull the characters after the decimal place?
I have a function named computeFare()
float computeFare()
{
totalFare = (3.40 + basicFare) * (1 + surchargePercent);
return totalFare; // **in this case totalFare = 34.567**
}
printf("Total fare is $%.2f\n",
computeFare());
Result : Total fare is $34.56
I did this and it returned 34.56...
I want it to be $34.57
Thanks,
Lawrence.
Not really, the number of decimal places is a function of the internal representation of the number. What you see when you display the number is, is the number as a string for printing.
So if you are interested in the displayed value, you can control the number of decimal places with formatting directives in the first place e.g., %5.2f, or use the string function approach as you mention in your post after the fact once you have the number as a string.
Also, as an aside, would you count trailing zeros?
Perhaps it would be helpful to state your goal for wanting to do this? There might be other ways to accomplish what you are looking to do.
Update:
Based on your update, the problem is really not counting decimal places, rather you are running into represenation issue/rounding errors (not that uncommon). The problem is that some fractional values can't be exactly represented in base 2. Here's an exhaustive explanation: What Every Computer Scientist Should Know About Floating-Point Arithmetic.
Take a look at this SO question: Understanding floating point representation errors; what's wrong with my thinking?
You can try this approach to round the value:
float rounded_val = floorf(value * 100.0 + 0.5) / 100.0;
Wikipeadia has a whole article on rounding.
The numbers will (in general) be stored in base 2, so fractional numbers are unlikely to correspond precisely to concise decimal strings. In order to get neat decimals, you're probably going to have to round first.
With printf you can specify the amount of decimal places.
%.0f equals no decimal places
%.4f equals float showing four decimal places
A. I wouldn't think so. even if you could get the mantisa (the exponent value) it would be in base 2.
B. Moreover, floating numbers are not accurate so most likely that if you don't have a perfect round number that you have infinite number of decimal places. you wouldn't see them when you print the number cause there are getting cut.
After your latest edit, it sounds like you just want to round, not that you really care about the number of decimal places in a number.
If this is the case you can use code like this:
#include <math.h>
float computeFare()
{
float totalFare;
totalFare = (3.40 + basicFare) * (1 + surchargePercent);
totalFare = floorf(totalFare * 100 + 0.5) / 100; //round the answer
return totalFare; // **in this case totalFare = 34.567**
}
printf("Total fare is $%.2f\n", computeFare());

Is it possible to round a double using just a printf statement?

Obviously this is just a fraction of the code.
printf("Please enter a positive number that has a fractional part with three or more decimal places\n");
scanf("%5.2d", &x);
printf("The number you have entered is %5.2d\n" ,x);
Would this automatically round the number I type in? Or is there another way to do this?
Edit:
printf("Please enter a positive number that has a fractional part with three or more decimal places\n");
scanf("%lf", &x);
x = x + 0.05;
printf( "The number you have entered is %5.2lf\n", x);
Iv done this, but Im taking into consideration what someone had said about printf just "changing" the way it reads out. So this is obviously not the right way. Should I implement maybe the pow() function? Will that work with this somehow?
Edit2:
printf("Please enter a positive number that has a fractional part with three or more decimal places\n");
scanf("%lf", &x);
x = x + 0.05;
printf( "The number you have entered is %5.2lf\n", x);
Okay, iv gotten to the point where if i imput a number it will round to a whole number. 35.21 will round to 35, and 35.51 will round to 36 et. etc.
How would I get 35.2178 to round to 35.22, and 35.2135 to round to 35.21.
How would I get the certain powers of the decimal to round instead of the whole number?
You really, really should not store "rounded" values in floating point variables. Floating point inaccuracy will ruin this - your 5.10 might become 5.099999999941892 simply because the implementation might not be able to store 5.10 exactly.
As an alternative, read the whole number, multiply it with 100 and convert it to int (which will round it towards zero). That will keep your calculations accurate.
"%.2f" will round a double to 2 digits. A double is not an integer, and %d and %f are not interchangeable.
{
float x;
float rounded_x;
printf("Please enter a positive number that has a fractional part with three or more decimal places\n");
scanf("%f", &x);
rounded_x = ((int)(x * 100 + .5) / 100.0);
printf( "The number you have entered is %.2f\n", rounded_x);
return 0;
}
Thank you to everyone who tried to help! I finally got it
printf won't change the value of the number, just how it is displayed. An alternative is
#include <math.h>
// round double x to 2 decimal places
x = 0.01 * floor(x * 100.0 + 0.5);
This doesn't make sense
scanf("%5.2d", &x);
You can't have an integer with numbers after the decmal point. if x is a flat then weird things will happen. If its an integer why are you after 2 decimal places in the printf.
What exactly are you trying to do?
Edit:
double x;
printf( "Please enter a positive number that has a fractional part with three or more decimal places\n" );
scanf( "%lf", &x );
printf( "The number you have entered is %5.2f\n", x + 0.005 );
I'm pretty sure printf only truncates. So you will need to add 0.005 to round it.

Resources