SCANF() NEWBIE
Author Message
SCANF() NEWBIE

I was hoping that someone could tell me why I can't scan in a number
and then multiply it times 100 without resulting in a number that's
off by one, but only in some cases???

Thanks,
Ron

#include <stdio.h>

void main(void)

{
int pennies, nickels, dimes, quarters;
int dollar, amnt100;
float amnt;

printf("Enter dollar amount in decimal format: ");
scanf("%f", &amnt);
amnt100 = amnt * 100;

Quote:
}

Input of 67.67 results in an assignment of 6766 to variable amnt100.

Some other values:
Input           amnt100

67.60         **6759**
67.61           6761
67.62           6762
67.63         **6762**
67.64         **6763**
67.65           6765
67.66           6766
67.67         **6766**
67.68           6768
67.69           6769
--

Wed, 07 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

Quote:

>I was hoping that someone could tell me why I can't scan in a number
>and then multiply it times 100 without resulting in a number that's
>off by one, but only in some cases???

Sure.

It has to do with two things.  1) float does not represent some
numbers precisely.  2) A conversion to int truncates away the decimal
places.  (It doesn't round.)

Quote:
>Thanks,
>Ron

>#include <stdio.h>

>void main(void)

"I'm sorry, but I'm going to have to shoot you." -Monty python
(quote or paraphrase?)

Per the Standard, main() is required to return int unless you
have a freestanding installation.  If you don't know what that is, you
don't have one (almost certainly).  A freestanding installation would
be as in an embedded control system.

Quote:
>{
>    int pennies, nickels, dimes, quarters;
>    int dollar, amnt100;
>    float amnt;

>    printf("Enter dollar amount in decimal format: ");
>    scanf("%f", &amnt);
>    amnt100 = amnt * 100;
>}

>    Input of 67.67 results in an assignment of 6766 to variable amnt100.

More precisely, on your system, input of "67.67" results in an
assignment of just under 67.67 to the float.  This multiplied by 100
is just under 6767 and the conversion to int truncates the decimal
places.  Voila 6766.

My kludge would be
amnt100=amnt*100+.005;
which will effectively result in rounding.  Others more knowledgeable
may have better ways.

Quote:
>    Some other values:
>                            Input           amnt100

>                            67.60         **6759**
>                            67.61           6761
>                            67.62           6762
>                            67.63         **6762**
>                            67.64         **6763**
>                            67.65           6765
>                            67.66           6766
>                            67.67         **6766**
>                            67.68           6768
>                            67.69           6769

The same sort of logic applies to your other cases.

Sincerely,

Gene Wirchenko

Computerese Irregular Verb Conjugation:
I have preferences.
You have biases.
He/She has prejudices.
--

Fri, 09 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

Quote:
>I was hoping that someone could tell me why I can't scan in a number
>and then multiply it times 100 without resulting in a number that's
>off by one, but only in some cases???

>Thanks,
>Ron

>#include <stdio.h>

>void main(void)

^^^^
ugh! should be int

Quote:

>{
>       int pennies, nickels, dimes, quarters;
>       int dollar, amnt100;
>       float amnt;

>       printf("Enter dollar amount in decimal format: ");
>       scanf("%f", &amnt);
>       amnt100 = amnt * 100;
>}

Because of the limitations of the internal (usually binary)
representation of floats and its subsequent conversion to int.  It has
little to do with the fact that you scanned in the values.

This is one of numerous reasons why you should not use floating point
types for financial calculations.

Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
--

Fri, 09 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

Quote:

> I was hoping that someone could tell me why I can't scan in a number
> and then multiply it times 100 without resulting in a number that's
> off by one, but only in some cases???

> Thanks,
> Ron

> #include <stdio.h>

> void main(void)

> {
>         int pennies, nickels, dimes, quarters;
>         int dollar, amnt100;
>         float amnt;

>         printf("Enter dollar amount in decimal format: ");
>         scanf("%f", &amnt);
>         amnt100 = amnt * 100;
> }

>         Input of 67.67 results in an assignment of 6766 to variable amnt100.

>         Some other values:
>                                 Input           amnt100

>                                 67.60         **6759**
>                                 67.61           6761
>                                 67.62           6762
>                                 67.63         **6762**
>                                 67.64         **6763**
>                                 67.65           6765
>                                 67.66           6766
>                                 67.67         **6766**
>                                 67.68           6768
>                                 67.69           6769
> --

You are caught by the difference between decimal & binary.  In decimal, rhink
of the number 1/3 which is
written as 0.333...   Now, computers can only store a limited number of digits,
in this example, like 0.333333333

Multiple the truncated number by 3 and get 0.999999999  which is less than 1.
Converting to integer then gives 0.

Solution when you do this?  What you want to do is round the number, not
truncate it.
amnt100 = (int) floor(amnt * 100 + 0.5);
--

Fri, 09 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

Quote:

> I was hoping that someone could tell me why I can't scan in a number
> and then multiply it times 100 without resulting in a number that's
> off by one, but only in some cases???

Two problems.

Floating point numbers are stored in a complicated binary (base 2)
format.  For many floating point numbers, there is no exact binary
representation.  For example, when I enter 67.60 it is actually stored
as 67.5999985 (on my Win 95 box) and 67.61 is stored as 67.6100006.
This is the closest that the computer can get.

When you cast a float to an integer, it does not round to the nearest
integer: it simply drops off the fractional part.

So 6761.00006 truncates to 6761 (which is what you want)
but 6759.99985 truncates to 6759 (which is not what you want).

The simplest method to round to the nearest integer is to add 0.5 before
truncating.

int i;
float f = /* something */;

i = f+0.5;

or more neatly:

#define ROUND(x) (int)((x)+0.5)

i = ROUND(f);

--
########################################################################

Emmenjay Consulting Pty Ltd             http://www.zip.com.au/~emmenjay/

Computers *ARE* user-friendly.  You just need to be properly introduced.
--

Fri, 09 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

Quote:
>I was hoping that someone could tell me why I can't scan in
>a [floating point] number
>and then multiply it times 100 without resulting in a number that's
>off by one, but only in some cases???

In the decimal arithmetic we are used to deal with, we
are used to some fractions, like 1/3 or 2/3 not being
able to be expressed cleanly as a percentage.
Others, like 1/2, 1/4, 1/5, 1/10, 1/20, 1/100 can be
expressed cleanly as a percentage.  We don't lose precision
with these fractions.

As I am sure you know, we (almost always) store numbers in
a binary format when we work with computers.  This means we
lose precision with any fraction whose denominator is not
a power of two.
--

Fri, 09 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

Quote:

> I was hoping that someone could tell me why I can't scan in a number
> and then multiply it times 100 without resulting in a number that's
> off by one, but only in some cases???
> #include <stdio.h>
> void main(void)

> {
>    int pennies, nickels, dimes, quarters;
>    int dollar, amnt100;
>    float amnt;

>    printf("Enter dollar amount in decimal format: ");
>    scanf("%f", &amnt);
>    amnt100 = amnt * 100;
> }
>    Input of 67.67 results in an assignment of 6766 to variable amnt100.

Almost certainly because many numbers can't be stored exactly as floating
point numbers.
In this case 67.67 might be internally represented ad 67.6699999 which
when multiplied by 100 gives 6766.99999. When this number is converted to
an int the fraction is discarded leaving you with 6766.
Remember that just because a number can be exactly represnted in decimal
(eg 67.67) it might not be exactly representable in binary. (Which most
floating point systems use.)
(Just as, for example,  1/3 can't be represnted exactly with decimal digits
(0.3333333...) while it would be a perfectly nice number in base-3 notation.

--
Erik Trulsson

--

Fri, 09 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

Quote:

> I was hoping that someone could tell me why I can't scan in a number
> and then multiply it times 100 without resulting in a number that's
> off by one, but only in some cases???

> Thanks,
> Ron

> #include <stdio.h>

> void main(void)

> {
>         int pennies, nickels, dimes, quarters;
>         int dollar, amnt100;
>         float amnt;

>         printf("Enter dollar amount in decimal format: ");
>         scanf("%f", &amnt);
>         amnt100 = amnt * 100;
> }

>         Input of 67.67 results in an assignment of 6766 to variable amnt100.

>         Some other values:
>                                 Input           amnt100

>                                 67.60         **6759**
>                                 67.61           6761
>                                 67.62           6762
>                                 67.63         **6762**
>                                 67.64         **6763**
>                                 67.65           6765
>                                 67.66           6766
>                                 67.67         **6766**
>                                 67.68           6768
>                                 67.69           6769

An old one but a good one.

This is nothing to do with scanf(). It is the simple consequence
of the fact that your ocmputer cannot store numbers of type
float particularly accurately. In fact on all the computers
Ive ever come across (recently!) it is impossible to store
numbers such as 67.67 exactly as this becomes a non-terminating
fraction in binary. It also looks as if your implementation
of printf() may be truncating rather than rounding on "f"
conversions.

For this sort of application you might consider using the
"double" data type although a better solution would be to
work entirely in "cents" as an integer data type using code
such as

int     pounds,pence;   /* Well I am British ! */
int     value;

printf("Enter sum ");
scanf("%d.%d",&pounds,&pence);
value  = pounds * 100 + pence;

printf("Money is %d.%02d\n",value/100,value%100);

Be careful with negative amounts !

Quote:
> --

--

--

Fri, 09 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

HMMMM...

int num;

scanf("%d" &num);

num*=100;

Is your code like this? If so, it SHOULD work!  dont forget
the  & in scanf!!!
--

Fri, 09 Mar 2001 03:00:00 GMT
SCANF() NEWBIE
The %f format expects a pointer to a *double*, not a float.

If you must use a float, the correct format is (hmm... access to long-term
(and probably unreliable) storage) "%hf".

--

Regards,

Quote:
> I was hoping that someone could tell me why I can't scan in a number
> and then multiply it times 100 without resulting in a number that's
> off by one, but only in some cases???

> Thanks,
> Ron

>    float amnt;

>    scanf("%f", &amnt);

--

Fri, 09 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

Quote:
>I was hoping that someone could tell me why I can't scan in a number
>and then multiply it times 100 without resulting in a number that's
>off by one, but only in some cases???

Do you have a clue about the floating point representations used by digital
computers?  If not, get one.  NOW!!!

Quote:
>    printf("Enter dollar amount in decimal format: ");
>    scanf("%f", &amnt);
>    amnt100 = amnt * 100;

amnt100 = amnt * 100 + 0.5;

will give you the expected result for positive values of amnt.
For negative values, subtract 0.5.

If you want to do financial computations in C, the easiest way is to use
double's and store the values expressed in cents, not dollars.  Simply
divide the results by 100 when you need to display them.

Things are bit more complicated when a thoroughly rigorous approach is
required, but my recipe above covers most usual situations.

Dan
--
Dan Pop
CERN, IT Division

Mail:  CERN - EP, Bat. 31 1-014, CH-1211 Geneve 23, Switzerland
--

Fri, 09 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

Quote:

>>I was hoping that someone could tell me why I can't scan in a number
>>and then multiply it times 100 without resulting in a number that's
>>off by one, but only in some cases???

>Do you have a clue about the floating point representations used by digital
>computers?  If not, get one.  NOW!!!

Wow, Dan, are you ever friendly to newbies!  If you can't be
civil to newbies, how about leaving their questions to those of us who
can?  It's not as if he was asking us to do his homework for him, so
your tone is out of line.

Being a newbie, how would he know what the cause of the problem
is?  If he can't handle a program such as the one he posted, he isn't
going to be able to dig into the minutiae of floating point
representation quite yet.

[snip]

Sincerely,

Gene Wirchenko

Computerese Irregular Verb Conjugation:
I have preferences.
You have biases.
He/She has prejudices.
--

Sat, 10 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

Quote:
>     My kludge would be
>          amnt100=amnt*100+.005;
>which will effectively result in rounding.  Others more knowledgeable
>may have better ways.

These are always hard, but as you intend to round to an int you need to
add .5 (though in this case the error will be way below that).  Also the
original writer should note that not all (in fact most) floats do not
convert into ints.  Even with a 64-bit int float covers many orders of
magnitude more values.

Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
--

Sat, 10 Mar 2001 03:00:00 GMT
SCANF() NEWBIE

Quote:
>The %f format expects a pointer to a *double*, not a float.

Since when?

Quote:
>If you must use a float, the correct format is (hmm... access to long-term
>(and probably unreliable) storage) "%hf".

Bullshit.  "%hf" is undefined behaviour.  The *correct* format for a float
is "%f" and it has been like that since K&R1.

Dan
--
Dan Pop
CERN, IT Division

Mail:  CERN - EP, Bat. 31 1-014, CH-1211 Geneve 23, Switzerland
--

Sat, 10 Mar 2001 03:00:00 GMT

 Page 1 of 3 [ 41 post ] Go to page: [1] [2] [3]

Relevant Pages