Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Converting Floats to Strings yields erratic results (http://www.velocityreviews.com/forums/t749566-converting-floats-to-strings-yields-erratic-results.html)

Dirk T. Shelley 06-07-2011 09:10 PM

Converting Floats to Strings yields erratic results
 
Hey all,
I'm writing, for my own personal enlightenment, a little program
that will convert a floating-point number, passed as an argument on
the command line, into a character string. I'm now aware of
sprintf(), but I wasn't when I started writing this program, and I
feel it is my duty to finish it ;-)

Everything, in general, works fine, except that some values are
converted to one less than their actual value. For example, 15
returns 15, 14.123 returns 14, but 14 returns 13. I am _completely_
clueless, although I suspect it has something to do with rounding and
truncating happening behind my back. The important part is as
follows...

while (foo >= 10) {
foo = foo/10.0;
tenDivs++;
}

i = 0;
while (tenDivs >= 0) {
while (!(foo < 1)) {
foo--;
oneDivs++;
}
str[i] = 48 + oneDivs;
foo = foo * 10;
oneDivs = 0;
tenDivs--;
i++;
}

Where "foo" is the value to be converted. Can anybody help, or point
me to a source that can?

In an unrelated question: Does anyone know of any link which describes
the (relative) performance of all kinds of C operations? e.g: how fast is
"add" comparing with "multiplication" on a typical machine.

Thanks!

Keith Thompson 06-07-2011 09:25 PM

Re: Converting Floats to Strings yields erratic results
 
"Dirk T. Shelley" <nospam@nospam.com> writes:
> I'm writing, for my own personal enlightenment, a little program
> that will convert a floating-point number, passed as an argument on
> the command line, into a character string. I'm now aware of
> sprintf(), but I wasn't when I started writing this program, and I
> feel it is my duty to finish it ;-)


Typically you *can't* pass floating-point numbers on the command line.
You can only pass strings. Presumably you convert those strings to
floating-point numbers somehow, but you don't tell us how.

> Everything, in general, works fine, except that some values are
> converted to one less than their actual value. For example, 15
> returns 15, 14.123 returns 14, but 14 returns 13. I am _completely_
> clueless, although I suspect it has something to do with rounding and
> truncating happening behind my back. The important part is as
> follows...


If you don't underrstand what's happening, how do you know that this is
the important part?

> while (foo >= 10) {
> foo = foo/10.0;


This will yield an inexact result (and for all we know the original
value of foo was inexact). Floating-point numbers are represented in
binary, not decimal.

Suggested reading: section 14 of the comp.lang.c FAQ,
<http://www.c-faq.com/>. For more advanced reading, search for
Goldberg's "What Every Computer Scientist Should Know About
Floating-Point Arithmetic".

> tenDivs++;
> }
>
> i = 0;
> while (tenDivs >= 0) {
> while (!(foo < 1)) {
> foo--;
> oneDivs++;
> }
> str[i] = 48 + oneDivs;


Where did the value 48 come from?

Oh, I see, it's the ASCII value of '0'. Just write '0' (yes, character
constants are of type int); it makes your code clearer and potentially
more portable. It assumes that the representations of '0' through '9'
are contiguous; as it happens, the language guarantees that.

> foo = foo * 10;
> oneDivs = 0;
> tenDivs--;
> i++;
> }
>
> Where "foo" is the value to be converted. Can anybody help, or point
> me to a source that can?


I haven't taken the time to analyze what your program is doing, but
consider this. As I mentioned above, dividing a floating-point
number x by 10.0 is likely to give you an inexact result.
Multiplying that result by 10.0 could give you something other than
the original number, and truncating that result could give you x - 1.

> In an unrelated question: Does anyone know of any link which describes
> the (relative) performance of all kinds of C operations? e.g: how fast is
> "add" comparing with "multiplication" on a typical machine.


I don't know. You can probably assume that addition is faster
than multiplication, and division is slower than either, but there
are no consistent guarantees. The relative performance of integer
and floating-point arithmetic can vary a great deal depending on
the hardware.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Eric Sosman 06-08-2011 12:47 AM

Re: Converting Floats to Strings yields erratic results
 
On 6/7/2011 5:10 PM, Dirk T. Shelley wrote:
> Hey all,
> I'm writing, for my own personal enlightenment, a little program
> that will convert a floating-point number, passed as an argument on
> the command line, into a character string. I'm now aware of
> sprintf(), but I wasn't when I started writing this program, and I
> feel it is my duty to finish it ;-)
>
> Everything, in general, works fine, except that some values are
> converted to one less than their actual value. For example, 15
> returns 15, 14.123 returns 14, but 14 returns 13. I am _completely_
> clueless, although I suspect it has something to do with rounding and
> truncating happening behind my back. The important part is as
> follows...
>
> while (foo>= 10) {
> foo = foo/10.0;


This line is "behind your back." On nearly every computer these
days, floating-point numbers use a base-two representation. A few
use base-sixteen, but the days of base-ten floating-point are pretty
much over and gone. (You'll still find it in hand-held calculators,
but you'll be hard-pressed to find it anywhere else.)

Consequence: You're dividing by 10, which is to say you're dividing
by 2*5. The 2 makes no trouble for a base-two system (and only a little
and subtler trouble for base-sixteen), but the 5 is a major problem.
It's very much like dividing by 35=5*7 in decimal: The 5 is no problem,
but the 7 is likely to involve an infinite repeating decimal fraction.
But just as you lack the patience to write out an infinite number of
fraction digits, the computer lacks the patience (and memory space) to
do the same. So you both stop writing digits after a while, round off
the result, and content yourselves with an approximate answer.

... which is why when you divide 14 by 10 you do not get exactly
1.4, but something close to it like 1.3999999999999999111821580299875.
Since this is just a smidgen less than you expected (it might turn out
to be a smidgen greater, depending on the particular values involved),
your subsequent calculations are likely to be off by just a little.
As you've seen...

> tenDivs++;
> }
>
> i = 0;
> while (tenDivs>= 0) {
> while (!(foo< 1)) {


This is *so* much clearer than `while(foo >= 1)' ...

> foo--;
> oneDivs++;
> }
> str[i] = 48 + oneDivs;


"48?" Funny choice of "digits" you've made. But then, you
haven't shown us how oneDivs was declared and initialized, so maybe
I'm worrying about nothing.

> foo = foo * 10;
> oneDivs = 0;


Okay, so for places beyond the first you're using PQRSTUVWXY as
"decimal digits" on a system with ASCII-compatible encodings, or
(unassigned)(unassigned)(SYN)(unassigned)(PN)(RS)( UC)(EOT)(unassigned)
(unassigned) on an EBCDIC system, or Lord knows what on some other
system. I repeat: Funny choice of "digits."

> tenDivs--;
> i++;
> }
>
> Where "foo" is the value to be converted. Can anybody help, or point
> me to a source that can?
>
> In an unrelated question: Does anyone know of any link which describes
> the (relative) performance of all kinds of C operations? e.g: how fast is
> "add" comparing with "multiplication" on a typical machine.


Yes! All sorts of people will tell you all sorts of things
about what operations are cheap or costly. And I'll let you in on
a secret: 99.44% of those people are full of fertilizer, and the
other 0.56% who aren't will say "Fuhgeddaboudit." Like the days of
decimal floating-point, the days of "multiply is slower than add"
or "shift is faster than multiply" or "pointers are faster than
array indices" are long gone.

--
Eric Sosman
esosman@ieee-dot-org.invalid

Keith Thompson 06-08-2011 03:08 AM

Re: Converting Floats to Strings yields erratic results
 
Eric Sosman <esosman@ieee-dot-org.invalid> writes:
[...]
> This line is "behind your back." On nearly every computer these
> days, floating-point numbers use a base-two representation. A few
> use base-sixteen, but the days of base-ten floating-point are pretty
> much over and gone. (You'll still find it in hand-held calculators,
> but you'll be hard-pressed to find it anywhere else.)


Right[*].
[*] Here's the footnote. IBM has recently been
pushing decimal floating-point. See, for example,
<http://www.ibm.com/developerworks/wikis/display/WikiPtype/Decimal+Floating+Point>
(which claims that The C draft standard includes _Decimal32,
_Decimal64, and _Decimal128, but N1570 has nothing like that).

I thought I remembered that the were storing 3 decimal digits (1000
values) in 10 bits (1024 values), which is almost as efficient
space-wise as pure binary, but I can't find a reference to that.

[...]

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Peter Nilsson 06-08-2011 03:13 AM

Re: Converting Floats to Strings yields erratic results
 
Keith Thompson <ks...@mib.org> wrote:
> ...*Floating-point numbers are represented in
> binary, not decimal.


Perhaps you where guessing the OP's implementation, but the
C language does not require that.

--
Peter

Keith Thompson 06-08-2011 03:27 AM

Re: Converting Floats to Strings yields erratic results
 
Peter Nilsson <airia@acay.com.au> writes:
> Keith Thompson <ks...@mib.org> wrote:
>> ...*Floating-point numbers are represented in
>> binary, not decimal.

>
> Perhaps you where guessing the OP's implementation, but the
> C language does not require that.


You're right.

I don't *think* there are any existing C implementations that use
anything other than binary (or base 16, but that still represents the
significand in binary). IBM has decimal floating-point on some of its
systems, but not for the predefined types.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson 06-08-2011 03:30 AM

Re: Converting Floats to Strings yields erratic results
 
Thad Smith <ThadSmith@acm.org> writes:
> On 6/7/2011 2:10 PM, Dirk T. Shelley wrote:
>> I'm writing, for my own personal enlightenment, a little program
>> that will convert a floating-point number, passed as an argument on
>> the command line, into a character string. I'm now aware of
>> sprintf(), but I wasn't when I started writing this program, and I
>> feel it is my duty to finish it ;-)

>
> You have received at least three responses now with a combination of helpful
> comments and cheap shots. It's awfully easy to say "that's a strange way" (in a
> derogatory manner) to someone just learning what the language supports and not
> knowing the idioms developed over time.
>
> Ignore the pot shots. Pay attention to the posters that have the knowledge and
> patience to help others without making cutting remarks.


Maybe my news server has better filtering than yours. I haven't seen
anything in this thread that I'd consider snide. In particular,
I just checked and there are no other responses with the phrase
"that's a strange way".

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Thad Smith 06-08-2011 03:38 AM

Re: Converting Floats to Strings yields erratic results
 
On 6/7/2011 2:10 PM, Dirk T. Shelley wrote:
> Hey all,
> I'm writing, for my own personal enlightenment, a little program
> that will convert a floating-point number, passed as an argument on
> the command line, into a character string. I'm now aware of
> sprintf(), but I wasn't when I started writing this program, and I
> feel it is my duty to finish it ;-)


Dirk,

You have received at least three responses now with a combination of helpful
comments and cheap shots. It's awfully easy to say "that's a strange way" (in a
derogatory manner) to someone just learning what the language supports and not
knowing the idioms developed over time.

Ignore the pot shots. Pay attention to the posters that have the knowledge and
patience to help others without making cutting remarks.


--
Thad

Eric Sosman 06-08-2011 03:38 AM

Re: Converting Floats to Strings yields erratic results
 
On 6/7/2011 11:08 PM, Keith Thompson wrote:
> Eric Sosman<esosman@ieee-dot-org.invalid> writes:
> [...]
>> This line is "behind your back." On nearly every computer these
>> days, floating-point numbers use a base-two representation. A few
>> use base-sixteen, but the days of base-ten floating-point are pretty
>> much over and gone. (You'll still find it in hand-held calculators,
>> but you'll be hard-pressed to find it anywhere else.)

>
> Right[*].
>
>[*] Here's the footnote. IBM has recently been
> pushing decimal floating-point. See, for example,
> <http://www.ibm.com/developerworks/wikis/display/WikiPtype/Decimal+Floating+Point>
> (which claims that The C draft standard includes _Decimal32,
> _Decimal64, and _Decimal128, but N1570 has nothing like that).


Right [**].

[**] The last decimal F-P "computer" (as opposed to "calculator")
I used was an IBM system. In the Johnson administration.[***]

[***] Sorry, ambiguous: I mean the Johnson who became President
when his predecessor was assassinated.[****]

[****] Coincidence? YOU be the judge!

--
Eric Sosman
esosman@ieee-dot-org.invalid

Eric Sosman 06-08-2011 03:49 AM

Re: Converting Floats to Strings yields erratic results
 
On 6/7/2011 8:47 PM, Eric Sosman wrote:
> On 6/7/2011 5:10 PM, Dirk T. Shelley wrote:
>> [...]
>> str[i] = 48 + oneDivs;

>
> "48?" Funny choice of "digits" you've made.[...]


My mistake (and not my first, or last). I sort of thought
you probably meant '0' and double-checked by looking at an ASCII
table, and its formatting fooled me.

In any event, though, you should write '0' when you want the
integer that encodes the digit zero, not 48 or 240 or 30[*].
[*] Trivia question.

--
Eric Sosman
esosman@ieee-dot-org.invalid


All times are GMT. The time now is 09:10 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.