How to round a float by casting as an int in C - c

So I am a second semester freshman in college. My teacher wants us to write a function that round a floating point number to the nearest hundredth. He said that we need to convert the floating point into an integer data type and then covert it back to a floating point. That's all he said. I have spent at least 5 hours trying different ways to do this.
This is my code so far:
#include <stdio.h>
int rounding(int roundedNum);
int main()
{
float userNum,
rounded;
printf("\nThis program will round a number to the nearest hundredths\n");
printf("\nPlease enter the number you want rounded\n>");
scanf("%f", &userNum);
rounded = rounding (userNum);
printf("%f rounded is %f\n", userNum, rounded);
return 0;
}
int rounding(int roundedNum)
{
return roundedNum;
}

Your instructor may be thinking:
float RoundHundredth(float x)
{
// Scale the hundredths place to the integer place.
float y = x * 100;
// Add .5 to cause rounding when converting to an integer.
y += .5f;
// Convert to an integer, which truncates.
int n = y;
// Convert back to float, undo scaling, and return.
return n / 100.f;
}
This is a flawed solution because:
Most C implementations use binary floating point. In binary floating-point, it is impossible to store any fractions that are not multiples of a negative power of two (½, ¼, ⅛, 1/16, 1/32, 1/64,…). So 1/100 cannot be exactly represented. Therefore, no matter what calculations you do, it is impossible to return exactly .01 or .79. The best you can do is get close.
When you perform arithmetic on floating-point numbers, the results are rounded to the nearest representable value. This means that, in x * 100, the result is, in generally, not exactly 100 times x. There is a small error due to rounding. This error cause push the value across the point where rounding changes from one direction to another, so it can make the answer wrong. There are techniques for avoiding this sort of error, but they are too complicated for introductory classes.
There is no need to convert to an integer to get truncation; C has a truncation function for floating-point built-in: trunc for double and truncf for float.
Additionally, the use of truncation in converting to integer compelled us to add ½ to get rounding instead. But, once we are no longer using a conversion to an integer type to get an integer value, we can use the built-in function for rounding floating-point values to integer values: round for double and roundf for float.
If your C implementation has good formatted input/output routines, then an easy way to find the value of a floating-point number rounded to the nearest hundred is to format it (as with snprintf) using the conversion specifier %.2f. A proper C implementation will convert the number to decimal, with two digits after the decimal point, using correct rounding that avoids the arithmetic rounding errors mentioned above. However, then you will have the number in string form.

Here are some hints:
Multiply float with "some power of 10" to ensure the needed precision numbers are shifted left
Cast the new value to a new int variable so the unwanted float bits are discarded
Divide the int by the same power of 10 but add use a float form of that (e.g 10.0) so integer gets converted to float and the new value is the correct value
To test, use printf with the precision (.2f)

The two most common methods of rounding are "Away From Zero" and "Banker's Rounding (To Even)".
Pseudo-code for Rounding Away From Zero
EDIT Even though this is pseudo-code, I should have included the accounting for precision, since we are dealing with floating-point values here.
// this code is fixed for 2 decimal places (n = 2) and
// an expected precision limit of 0.001 (m = 3)
// for any values of n and m, the first multiplicand is 10^(n+1)
// the first divisor is 10^(m + 1), and
// the final divisor is 10^(n)
double roundAwayFromZero(double value) {
boolean check to see if value is a negative number
add precision bumper of (1.0 / 10000) to "value" // 10000.0 is 10^4
multiply "value" by 1000.0 and cast to (int) // 1000.0 is 10^3
if boolean check is true, negate the integer to positive
add 5 to integer result, and divide by 10
if boolean check is true, negate the integer again
divide the integer by 100.0 and return as double // 100.0 is 10^2
ex: -123.456
true
-123.456 + (1.0 / 10000.0) => -123.4561
-123.4561 * 1000.0 => -123456.1 => -123456 as integer
true, so => -(-123456) => 123456
(123456 + 5) / 10 => 123461 / 10 => 12346
true, so => -(12346) => -12346
-12346 / 100.0 => -123.46 ===> return value
}
In your initial question, you expressed a desire for direction only, not the explicit answer in code. This is as vague as I can manage to make it while still making any sense. I'll leave the "Banker's Rounding" version for you to implement as an exercise.

Ok so I figured it out! thank yall for your answers.
//function
float rounding(float roundedNumber)
{
roundedNumber = roundedNumber * 100.0f + 0.5f;
roundedNumber = (int) roundedNumber * 0.01f;
return roundedNumber;
}
So pretty much if I entered 56.12567 as roundedNumber, it would multiply by 100 yielding 5612.567. From there it would add .5 which would determine if it rounds up. In this case, it does. The number would change to 5613.067.
Then you truncate it by converting it into a int and multiply by .01 to get the decimal back over. From there it returns the value to main and prints out the rounded number. Pretty odd way of rounding but I guess thats how you do it in C without using the rounding function.

Well, let's think about it. One thing that's helpful to know is that we can turn a float into an integer by casting:
float x = 5.4;
int y = (int) x;
//y is now equal to 5
When we cast, the float is truncated, meaning that whatever comes after the decimal point is dropped, regardless of its value (i.e. It always rounds towards 0).
So if you think about that and the fact that you care about the hundredths place, you could maybe imagine an approach that consists of manipulating your floating point number in someway such that when you cast it to an int you only truncate information you don't care about (i.e. digits past the hundredths place). Multiplying might be useful here.

Related

discrepancies in rounding off in C

I'm having an issue where when I print a double value it is inconsistently either rounding up or down. I am using the format:
printf("%.2lf", double);
what could be the possible issue here? thanks!
Any decimal numeral in source code or input is converted to the binary format your C implementation uses for double. This changes the value away from the xxx.xx5 value. When it is then printed using %.2lf, it is the changed value that is rounded, not the original. There is no way to avoid this using only the value in a double.
With additional information, such as known limits on how many decimal digits the original numerals had or what values they may take, it might be possible to reconstruct the original value and round that. However, such information is not present in the question.
"fraction is exact at the 3rd decimal point"
As double uses a binary internal representation, most decimal fractions like 0.1, 0.01, 0.001 are not possible to represent exactly. Instead of the exact code value of x.xx5, a double near that is used, perhaps a tad lower or higher.
To recover that exact at the 3rd decimal point, scale the double by 1000.0 and round to nearest whole number.
double d1000 = round(d * 1000.0);
To print to 2 decimal places, round the d1000 to the nearest 10s, round and then divide by 100.0
double d100 = round(d1000 / 10.0) / 100.0;
printf("%.2lf", double);
In effect, code recovers by employing a double rounding.
Example:
#include <stdio.h>
#include <math.h>
void prt(double d) {
double d1000 = round(d * 1000.0);
double d100 = round(d1000 / 10.0) / 100.0;
printf("%.16e %.2lf\n", d, d100);
}
void prt3(double d) {
prt(nextafter(d, 0));
prt(d);
prt(nextafter(d, d*2));
}
int main() {
prt3(1203.505000);
prt3(1203.705000);
}
Output
1.2035049999999999e+03 1203.51
1.2035050000000001e+03 1203.51
1.2035050000000003e+03 1203.51
1.2037049999999997e+03 1203.71
1.2037049999999999e+03 1203.71
1.2037050000000002e+03 1203.71
In a comment you wrote
the fraction is exact at the 3rd decimal point
Your original number might have been, but once it's converted to double, which uses binary fractions internally, there's no such thing as a "third decimal point", and in fact decimal numbers like 0.001 and 0.005 simply cannot be represented exactly.
Here are some sample numbers, how they're represented as a double, and how they print as "%.2lf, that is, converted back to decimal and rounded to two places.
(Note that when I say "how they're represented as a double", what I'm really showing you is the internal binary representation converted back to decimal again. It's also interesting to look at the actual internal representation, in binary or hexadecimal, but it's harder to display meaningfully and doesn't really bear on today's question, so I'm not going to bother.)
input value
internal double value
printed "%.2lf"
1203.480
1203.4800000000000181899
1203.48
1203.485
1203.4849999999998999556
1203.48
1203.490
1203.4900000000000090949
1203.49
1203.495
1203.4949999999998908606
1203.49
1203.500
1203.5000000000000000000
1203.50
1203.505
1203.5050000000001091394
1203.51
1203.510
1203.5099999999999909051
1203.51
1203.515
1203.5150000000001000444
1203.52
1203.520
1203.5199999999999818101
1203.52
1203.525
1203.5250000000000909495
1203.53
1203.530
1203.5299999999999727152
1203.53
You can see that sometimes .xx5 is represented as .xx50000000001 and so rounds up as you expect, but sometimes it's represented as .xx49999999999 and so rounds down.
You asked "what could be the possible issue here", and that's what I've explained. Other answers contain suggestions on how you could adjust your code to work around the issue.

Using floorf to reduce the number of decimals

I would like to use the first five digits of a number for computation.
For example,
A floating point number: 4.23654897E-05
I wish to use 4.2365E-05.I tried the following
#include <math.h>
#include <stdio.h>
float num = 4.23654897E-05;
int main(){
float rounded_down = floorf(num * 10000) / 10000;
printf("%f",rounded_down);
return 0;
}
The output is 0.000000.The desired output is 4.2365E-05.
In short,say 52 bits are allocated for storing the mantissa.Is there a way to reduce the number of bits being allocated?
Any suggestions on how this can be done?
A number x that is positive and within the normal range can be rounded down approximately to five significant digits with:
double l = pow(10, floor(log10(x)) - 4);
double y = l * floor(x / l);
This is useful only for tinkering with floating-point arithmetic as a learning tool. The exact mathematical result is generally not exactly representable, because binary floating-point cannot represent most decimal values exactly. Additionally, rounding errors can occur in the pow, /, and * operations that may cause the result to differ slightly from the true mathematical result of rounding x to five significant digits. Also, poor implementations of log10 or pow can cause the result to differ from the true mathematical result.
I'd go:
printf("%.6f", num);
Or you can try using snprintf() from stdlib.h:
float num = 4.23654897E-05; char output[50];
snprintf(output, 50, "%f", num);
printf("%s", output);
The result is expected. The multiplication by 10000 yield 0.423.. the nearest integer to it is 0. So the result is 0. Rounding can be done using format specifier %f to print the result upto certain decimal places after decimal point.
If you check the return value of floorf you will see it returns If no errors occur, the largest integer value not greater than arg, that is ⌊arg⌋, is returned. where arg is the passed argument.
Without using floatf you can use %e or (%E)format specifier to print it accordingly.
printf("%.4E",num);
which outputs:
4.2365E-05
After David's comment:
Your way of doing things is right but the number you multiplied is wrong. The thing is 4.2365E-05 is 0.00004235.... Now if you multiply it with 10000 then it will 0.42365... Now you said I want the expression to represent in that form. floorf returns float in this case. Store it in a variable and you will be good to go. The rounded value will be in that variable. But you will see that the rounded down value will be 0. That is what you got.
float rounded_down = floorf(num * 10000) / 10000;
This will hold the correct value rounded down to 4 digits after . (not in exponent notation with E or e). Don't confuse the value with the format specifier used to represent it.
What you need to do in order to get the result you want is move the decimal places to the right. To do that multiply with larger number. (1e7 or 1e8 or as you want it to).
I would like to use the first five digits of a number for computation.
In general, floating point numbers are encoded using binary and OP wants to use 5 significant decimal digits. This is problematic as numbers like 4.23654897E-05 and 4.2365E-05 are not exactly representable as a float/double. The best we can do is get close.
The floor*() approach has problems with 1) negative numbers (should have used trunc()) and 2) values near x.99995 that during rounding may change the number of digits. I strongly recommend against it here as such solutions employing it fail many corner cases.
The *10000 * power10, round, /(10000 * power10) approach suffers from 1) power10 calculation (1e5 in this case) 2) rounding errors in the multiple, 3) overflow potential. The needed power10 may not be exact. * errors show up with cases when the product is close to xxxxx.5. Often this intermediate calculation is done using wider double math and so the corner cases are rare. Bad rounding using (some_int_type) which has limited range and is a truncation instead of the better round() or rint().
An approach that gets close to OP's goal: print to 5 significant digits using %e and convert back. Not highly efficient, yet handles all cases well.
int main(void) {
float num = 4.23654897E-05f;
// sign d . dddd e sign expo + \0
#define N (1 + 1 + 1 + 4 + 1 + 1 + 4 + 1)
char buf[N*2]; // Use a generous buffer - I like 2x what I think is needed.
// OP wants 5 significant digits so print 4 digits after the decimal point.
sprintf(buf, "%.4e", num);
float rounded = (float) atof(buf);
printf("%.5e %s\n", rounded, buf);
}
Output
4.23650e-05 4.2365e-05
Why 5 in %.5e: Typical float will print up to 6 significant decimal digits as expected (research FLT_DIG), so 5 digits after the decimal point are printed. The exact value of rounded in this case was about 4.236500171...e-05 as 4.2365e-05 is not exactly representable as a float.

Add zeros in the right hand of a float number

I need to do this (does not round, floor or ceil):
example:
1.58700023 (16bits)
expected 1.58700000
i am doing this operation: (value-32768.0)/32768 to convert to (byte value to real value in float) int his conversion have this error = X.00000023 or others
It's quite possible that you cannot do this with floats; note that not all values are exactly representable as a float: it's limited to 32 (typically) bits after all.
For printing, you should be able to use:
printf("%.3f", 1.58700023);
This will print 1.587 by rounding as the value is converted to string.
I assume you want to implement rounding with primitives.
To round to four decimal places, multiply with 10e4, convert to integer (effectively truncating or removing the decimals), then divide by float value 10e4 which converts the result back to float again. For example:
#include <stdio.h>
int main()
{
double f = 1.58700023;
printf("%10.10f\n", f);
// Round to 4 decimal places
double r = (int)(f*10000.0)/10000.0;
printf("%10.10f\n", r);
return 0;
}
This outputs:
1.5870002300
1.5870000000
There are many edge cases not supported by this routine, though. E.g., you may want to add one half of 1/10e4 to perform rounding to nearest next digit, etc.

c floating point round down

If I run the following:
int tokenIdx=ERROR; //ERROR=8
tokens[tokenIdx] = 57; //tokens is of type int[]
int totalTokens = 100;
int percent = (int)((100.0 * tokens[tokenIdx])/(float)totalTokens);
printf("%d%\n",percent);
int percent2 = (int)(100.0*(tokens[tokenIdx]/(1.0*totalTokens)));
printf("%d%\n",percent2);
the output is:
57%
56%
Why is this happening?
Because 5700.0 and 100.0 can both be represented exactly as floating point numbers, and their ratio is exactly 57.0. On the other hand, 57.0/100.0 cannot be represented exactly as a floating pointer number, and multiplying it by 100.0 will not produced exactly 57.0. If it produces slightly less than 57.0 (as seems to be the case), then casting to (int), which truncates, will result in the integer 56.
Floating point rounding error. In your first case, you're doing a double divided by a float, in the second, it's a double divided by a double. The int conversion is throwing away the fractional portion, which in the second case is probably .999999999998 or something like it.
Lessons learned: floating point isn't precise, mind your conversions, watch your types
If you really honestly want an integer percentage, do:
int percent = 100 * value / total;
where value and total are both ints.
If you need more precision (say 10ths), consider doing it in thousands or and dividing down to float:
float percent = (1000 * value / total) / 10f;
Provided that 1000 * value won't overflow in your problem domain.

Multiplying two floats doesn't give exact result

I am trying to multiply two floats as follows:
float number1 = 321.12;
float number2 = 345.34;
float rexsult = number1 * number2;
The result I want to see is 110895.582, but when I run the code it just gives me 110896. Most of the time I'm having this issue. Any calculator gives me the exact result with all decimals. How can I achive that result?
edit : It's C code. I'm using XCode iOS simulator.
There's a lot of rounding going on.
float a = 321.12; // this number will be rounded
float b = 345.34; // this number will also be rounded
float r = a * b; // and this number will be rounded too
printf("%.15f\n", r);
I get 110895.578125000000000 after the three separate roundings.
If you want more than 6 decimal digits' worth of precision, you will have to use double and not float. (Note that I said "decimal digits' worth", because you don't get decimal digits, you get binary.) As it stands, 1/2 ULP of error (a worst-case bound for a perfectly rounded result) is about 0.004.
If you want exactly rounded decimal numbers, you will have to use a specialized decimal library for such a task. A double has more than enough precision for scientists, but if you work with money everything has to be 100% exact. No floating point numbers for money.
Unlike integers, floating point numbers take some real work before you can get accustomed to their pitfalls. See "What Every Computer Scientist Should Know About Floating-Point Arithmetic", which is the classic introduction to the topic.
Edit: Actually, I'm not sure that the code rounds three times. It might round five times, since the constants for a and b might be rounded first to double-precision and then to single-precision when they are stored. But I don't know the rules of this part of C very well.
You will never get the exact result that way.
First of all, number1 ≠ 321.12 because that value cannot be represented exactly in a base-2 system. You'll need an infinite number of bits for it.
The same holds for number2 ≠ 345.34.
So, you begin with inexact values to begin with.
Then the product will get rounded because multiplication gives you double the number of significant digits but the product has to be stored in float again if you multiply floats.
You probably want to use a 10-based system for your numbers. Or, in case your numbers only have 2 decimal digits of the fractional, you can use integers (32-bit integers are sufficient in this case, but you may end up needing 64-bit):
32112 * 34534 = 1108955808.
That represents 321.12 * 345.34 = 110895.5808.
Since you are using C you could easily set the precision by using "%.xf" where x is the wanted precision.
For example:
float n1 = 321.12;
float n2 = 345.34;
float result = n1 * n2;
printf("%.20f", result);
Output:
110895.57812500000000000000
However, note that float only gives six digits of precision. For better precision use double.
floating point variables are only approximate representation, not precise one. Not every number can "fit" into float variable. For example, there is no way to put 1/10 (0.1) into binary variable, just like it's not possible to put 1/3 into decimal one (you can only approximate it with endless 0.33333)
when outputting such variables, it's usual to apply many rounding options. Unless you set them all, you can never be sure which of them are applied. This is especially true for << operators, as the stream can be told how to round BEFORE <<.
Printf also does some rounding. Consider http://codepad.org/LLweoeHp:
float t = 0.1f;
printf("result: %f\n", t);
--
result: 0.100000
Well, it looks fine. Why? Because printf defaulted to some precision and rounded up the output. Let's dial in 50 places after decimal point: http://codepad.org/frUPOvcI
float t = 0.1f;
printf("result: %.50f\n", t);
--
result: 0.10000000149011611938476562500000000000000000000000
That's different, isn't it? After 625 the float ran out of capacity to hold more data, that's why we see zeroes.
A double can hold more digits, but 0.1 in binary is not finite. Double has to give up, eventually: http://codepad.org/RAd7Yu2r
double t = 0.1;
printf("result: %.70f\n", t);
--
result: 0.1000000000000000055511151231257827021181583404541015625000000000000000
In your example, 321.12 alone is enough to cause trouble: http://codepad.org/cgw3vUKn
float t = 321.12f;
printf("and the result is: %.50f\n", t);
result: 321.11999511718750000000000000000000000000000000000000
This is why one has to round up floating point values before presenting them to humans.
Calculator programs don't use floats or doubles at all. They implement decimal number format. eg:
struct decimal
{
int mantissa; //meaningfull digits
int exponent; //number of decimal zeroes
};
Ofc that requires reinventing all operations: addition, substraction, multiplication and division. Or just look for a decimal library.

Resources