Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #5617 > unrolled thread
| Started by | "Dirk T. Shelley" <nospam@nospam.com> |
|---|---|
| First post | 2011-06-07 21:10 +0000 |
| Last post | 2011-06-08 21:56 -0400 |
| Articles | 20 on this page of 32 — 15 participants |
Back to article view | Back to comp.lang.c
Converting Floats to Strings yields erratic results "Dirk T. Shelley" <nospam@nospam.com> - 2011-06-07 21:10 +0000
Re: Converting Floats to Strings yields erratic results Keith Thompson <kst-u@mib.org> - 2011-06-07 14:25 -0700
Re: Converting Floats to Strings yields erratic results Peter Nilsson <airia@acay.com.au> - 2011-06-07 20:13 -0700
Re: Converting Floats to Strings yields erratic results Keith Thompson <kst-u@mib.org> - 2011-06-07 20:27 -0700
Re: Converting Floats to Strings yields erratic results "Dirk T. Shelley" <nospam@nospam.com> - 2011-06-08 16:34 +0000
Re: Converting Floats to Strings yields erratic results Ian Collins <ian-news@hotmail.com> - 2011-06-09 07:53 +1200
Re: Converting Floats to Strings yields erratic results "Dirk T. Shelley" <nospam@nospam.com> - 2011-06-08 20:46 +0000
Re: Converting Floats to Strings yields erratic results "BartC" <bc@freeuk.com> - 2011-06-08 22:40 +0100
Re: Converting Floats to Strings yields erratic results "BartC" <bc@freeuk.com> - 2011-06-09 11:03 +0100
Re: Converting Floats to Strings yields erratic results James Kuyper <jameskuyper@verizon.net> - 2011-06-09 08:06 -0400
Re: Converting Floats to Strings yields erratic results "BartC" <bc@freeuk.com> - 2011-06-09 16:57 +0100
Re: Converting Floats to Strings yields erratic results Noob <root@127.0.0.1> - 2011-06-09 14:13 +0200
Re: Converting Floats to Strings yields erratic results Keith Thompson <kst-u@mib.org> - 2011-06-09 09:26 -0700
Re: Converting Floats to Strings yields erratic results "BartC" <bc@freeuk.com> - 2011-06-09 19:07 +0100
Re: Converting Floats to Strings yields erratic results Keith Thompson <kst-u@mib.org> - 2011-06-09 11:52 -0700
Re: Converting Floats to Strings yields erratic results "BartC" <bc@freeuk.com> - 2011-06-09 20:30 +0100
Re: Converting Floats to Strings yields erratic results "io_x" <a@b.c.invalid> - 2011-06-13 12:21 +0200
Re: Converting Floats to Strings yields erratic results "io_x" <a@b.c.invalid> - 2011-06-13 22:31 +0200
Re: Converting Floats to Strings yields erratic results Noob <root@127.0.0.1> - 2011-06-10 10:58 +0200
Re: Converting Floats to Strings yields erratic results Seebs <usenet-nospam@seebs.net> - 2011-06-10 22:49 +0000
Re: Converting Floats to Strings yields erratic results Eric Sosman <esosman@ieee-dot-org.invalid> - 2011-06-08 21:51 -0400
Re: Converting Floats to Strings yields erratic results Mark Bluemel <mark_bluemel@pobox.com> - 2011-06-09 08:50 +0100
Re: Converting Floats to Strings yields erratic results gordonb.9ycz5@burditt.org (Gordon Burditt) - 2011-06-07 18:13 -0500
Re: Converting Floats to Strings yields erratic results Eric Sosman <esosman@ieee-dot-org.invalid> - 2011-06-07 20:47 -0400
Re: Converting Floats to Strings yields erratic results Keith Thompson <kst-u@mib.org> - 2011-06-07 20:08 -0700
Re: Converting Floats to Strings yields erratic results Eric Sosman <esosman@ieee-dot-org.invalid> - 2011-06-07 23:38 -0400
Re: Converting Floats to Strings yields erratic results Eric Sosman <esosman@ieee-dot-org.invalid> - 2011-06-07 23:49 -0400
Re: Converting Floats to Strings yields erratic results Shao Miller <sha0.miller@gmail.com> - 2011-06-08 00:54 -0500
Re: Converting Floats to Strings yields erratic results Thad Smith <ThadSmith@acm.org> - 2011-06-07 20:38 -0700
Re: Converting Floats to Strings yields erratic results Keith Thompson <kst-u@mib.org> - 2011-06-07 20:30 -0700
Re: Converting Floats to Strings yields erratic results falk@rahul.net (Edward A. Falk) - 2011-06-08 20:54 +0000
Re: Converting Floats to Strings yields erratic results Eric Sosman <esosman@ieee-dot-org.invalid> - 2011-06-08 21:56 -0400
Page 1 of 2 [1] 2 Next page →
| From | "Dirk T. Shelley" <nospam@nospam.com> |
|---|---|
| Date | 2011-06-07 21:10 +0000 |
| Subject | Converting Floats to Strings yields erratic results |
| Message-ID | <ism43f$cg1$1@speranza.aioe.org> |
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!
[toc] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2011-06-07 14:25 -0700 |
| Message-ID | <lnpqmpe3lu.fsf@nuthaus.mib.org> |
| In reply to | #5617 |
"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"
[toc] | [prev] | [next] | [standalone]
| From | Peter Nilsson <airia@acay.com.au> |
|---|---|
| Date | 2011-06-07 20:13 -0700 |
| Message-ID | <ddc4e4f9-a182-405d-af6a-38c6889979d4@k15g2000pri.googlegroups.com> |
| In reply to | #5618 |
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
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2011-06-07 20:27 -0700 |
| Message-ID | <lnd3ipdmu7.fsf@nuthaus.mib.org> |
| In reply to | #5624 |
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"
[toc] | [prev] | [next] | [standalone]
| From | "Dirk T. Shelley" <nospam@nospam.com> |
|---|---|
| Date | 2011-06-08 16:34 +0000 |
| Message-ID | <iso8aa$9ng$1@speranza.aioe.org> |
| In reply to | #5618 |
Keith Thompson writes:
> "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.
Thanks for all the responses.
I think I now have a vague understanding of the nature of the
problem, though not enough to fix it. My complete code is as follows
if anyone cares to further pick it apart.
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[]) {
int tenDivs, oneDivs, i, neg_foo;
char str[sizeof(float)+1];
float foo;
/* Make sure the user entered a number, and retrieve it's value.
*/
switch (argc) {
case 1:
printf("Not enough arguments.\n");
exit(0);
break;
case 2:
foo = atof(argv[1]);
break;
default:
printf("Too many arguments.\n");
exit(0);
break;
}
tenDivs = 0;
oneDivs = 0;
neg_foo = 0;
/* if foo is a negative number, make it positive and take note */
if (foo < 0) {
foo = 0 - foo;
neg_foo = 1;
}
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++;
}
str[i] = '\0';
/* if foo was positive, we are done. */
if (neg_foo == 0)
printf("The value of str is: %s\n", str);
/* if foo was negative, adjust our value. */
if (neg_foo == 1) {
while (i >= 0) {
str[i+1] = str[i];
i--;
}
str[0] = '-';
printf("The value of str is: %s\n", str);
}
return 0;
}
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2011-06-09 07:53 +1200 |
| Message-ID | <95a29iFrnrU4@mid.individual.net> |
| In reply to | #5639 |
On 06/ 9/11 04:34 AM, Dirk T. Shelley wrote: > > Thanks for all the responses. > > I think I now have a vague understanding of the nature of the > problem, though not enough to fix it. My complete code is as follows > if anyone cares to further pick it apart. You don't appear to have addressed any of the issues people have pointed to to you. The most notable is the repeated division by 10. Try and fix those and see how you get on. <code snipped> -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | "Dirk T. Shelley" <nospam@nospam.com> |
|---|---|
| Date | 2011-06-08 20:46 +0000 |
| Message-ID | <ison35$gjf$1@speranza.aioe.org> |
| In reply to | #5654 |
Ian Collins writes: > On 06/ 9/11 04:34 AM, Dirk T. Shelley wrote: >> >> Thanks for all the responses. >> >> I think I now have a vague understanding of the nature of the problem, >> though not enough to fix it. My complete code is as follows if anyone >> cares to further pick it apart. > > You don't appear to have addressed any of the issues people have pointed > to to you. The most notable is the repeated division by 10. > > Try and fix those and see how you get on. > > <code snipped> As I said, I could do with a bit more help, Ian. Seeing that I want to get out the decimal representation, I don't really see how I can avoid working with tens.
[toc] | [prev] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2011-06-08 22:40 +0100 |
| Message-ID | <isoqbd$i94$1@dont-email.me> |
| In reply to | #5639 |
"Dirk T. Shelley" <nospam@nospam.com> wrote in message
news:iso8aa$9ng$1@speranza.aioe.org...
> while (foo >= 10) {
> foo = foo/10.0;
> tenDivs++;
> }
This code prints only the integral part? On my machine it shows 9 for foo up
to 9.999999, and 10 for 9.9999999.
Code to convert binary floating point to decimal is very tricky to write.
I've just had a go, and while the following sort of works, it's probably
full of numerical problems too.
It's not meant to be fast, so divisions etc are not optimised out, and
display of large/low magnitude numbers will be slow. Use of pow() is a bit
of a cheat (if there is no built-in way of stringifying a float, then you
probably won't have pow() either). But it can be replaced with a loop.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
/* print x using <dp> decimal places */
void printx(double x,int dp){
double y;
int digits=0;
int i;
if (dp<0) dp=0;
y=0.5*pow(10,-dp); /* y is eg. 0.0005 when dp=4 */
if (x<0.0) {
printf("-");
x=-x;
}
x+=y; /* possible round-up of last digit */
while (x>=1.0) { /* count digits before decimal point */
x=x/10.0;
++digits;
}
if (digits==0) printf("0");
for (i=0; i<(digits+dp); ++i) {
if (i==digits) printf(".");
x=x*10.0; /* x should be 1.0 to 9.999.. here */
printf("%d",(int)x); /* assume (int)x rounds down */
x=x-(int)x;
}
}
int main(void){
printx(1234.56789,3);
puts("");
}
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2011-06-09 11:03 +0100 |
| Message-ID | <isq5qc$4rv$1@dont-email.me> |
| In reply to | #5662 |
"BartC" <bc@freeuk.com> wrote in message news:isoqbd$i94$1@dont-email.me...
> Code to convert binary floating point to decimal is very tricky to write.
> I've just had a go, and while the following sort of works, it's probably
> full of numerical problems too.
My code introduces errors in the lower bits of the number. I'm trying to
compare the results to printf(), but if I write:
printf("%f\n",1.0e40);
I get an impossibly clean result of 1 followed by loads of zeros, no matter
what numbers I stick inside %f. Clearly 1e40 can't be stored exactly (can
it? I thought it would need over 120 bits of precision), so how can I tell
printf to show it as it is?
(If I print 1e50, then I've noticed there is a '1' amongst the zeros; that
can't be right either..)
--
bartc
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2011-06-09 08:06 -0400 |
| Message-ID | <isqcvb$9i7$1@dont-email.me> |
| In reply to | #5686 |
On 06/09/2011 06:03 AM, BartC wrote:
> "BartC" <bc@freeuk.com> wrote in message news:isoqbd$i94$1@dont-email.me...
>
>> Code to convert binary floating point to decimal is very tricky to write.
>> I've just had a go, and while the following sort of works, it's probably
>> full of numerical problems too.
>
> My code introduces errors in the lower bits of the number. I'm trying to
> compare the results to printf(), but if I write:
>
> printf("%f\n",1.0e40);
>
> I get an impossibly clean result of 1 followed by loads of zeros, no matter
> what numbers I stick inside %f. Clearly 1e40 can't be stored exactly (can
> it? I thought it would need over 120 bits of precision), so how can I tell
> printf to show it as it is?
>
> (If I print 1e50, then I've noticed there is a '1' amongst the zeros; that
> can't be right either..)
1e40 is 2^40*5^40. 2^40 is just absorbed into the exponent. 5^40
requires only 93 bits to be represented exactly, not 120. It's therefore
possible to store 1e40 exactly in a 128-bit type. I've heard of
implementations with 128-bit long double, but not 128-bit double.
With respect to %f, the standard says "The value is rounded to
the appropriate number of digits." (7.19.6.1p8). I think that this is a
little unclear, but it could be used to justify producing all zeros
after the last significant digit of the output string. That's what I've
usually seen real implementations do.
--
James Kuyper
[toc] | [prev] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2011-06-09 16:57 +0100 |
| Message-ID | <isqqjc$kb$1@dont-email.me> |
| In reply to | #5688 |
"James Kuyper" <jameskuyper@verizon.net> wrote in message
news:isqcvb$9i7$1@dont-email.me...
> On 06/09/2011 06:03 AM, BartC wrote:
>> "BartC" <bc@freeuk.com> wrote in message
>> news:isoqbd$i94$1@dont-email.me...
>> My code introduces errors in the lower bits of the number. I'm trying to
>> compare the results to printf(), but if I write:
>>
>> printf("%f\n",1.0e40);
>>
>> I get an impossibly clean result of 1 followed by loads of zeros, no
>> matter
>> what numbers I stick inside %f. Clearly 1e40 can't be stored exactly (can
>> it? I thought it would need over 120 bits of precision), so how can I
>> tell
>> printf to show it as it is?
>>
>> (If I print 1e50, then I've noticed there is a '1' amongst the zeros;
>> that
>> can't be right either..)
>
> 1e40 is 2^40*5^40. 2^40 is just absorbed into the exponent. 5^40
> requires only 93 bits to be represented exactly, not 120. It's therefore
> possible to store 1e40 exactly in a 128-bit type. I've heard of
> implementations with 128-bit long double, but not 128-bit double.
>
> With respect to %f, the standard says "The value is rounded to
> the appropriate number of digits." (7.19.6.1p8). I think that this is a
> little unclear, but it could be used to justify producing all zeros
> after the last significant digit of the output string. That's what I've
> usually seen real implementations do.
OK. The problem is that with a double set to 1e40, printf gives:
10000000000000000000000000000000000000000.000000
But using a bigint library to calculate the actual value stored in the bit
pattern, it gives:
10000000000000000303786028427003666890752
(although I might have expected a result just below 1e40), while the simple
code I posted earlier gives this result:
10000000000000004440892098500626161694526
So is not as bad as I thought! However my point was I couldn't figure how to
get printf to give me the true value (in decimal; I can't do anything with
the hex).
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Noob <root@127.0.0.1> |
|---|---|
| Date | 2011-06-09 14:13 +0200 |
| Message-ID | <isqdck$7ej$1@speranza.aioe.org> |
| In reply to | #5686 |
BartC wrote:
> Clearly 1e40 can't be stored exactly (can it?
> I thought it would need over 120 bits of precision)
1e40 = 10^40
= 5^40 * 2^40
= 0x1D6329F1C35CA4BFABB9F561 * 2^40
5^40 requires 93 bits to store precisely.
Thus, a double-precision IEEE 754 floating-point number
cannot store 1e40 exactly, as the mantissa is expressed
over (only) 52 bits.
http://en.wikipedia.org/wiki/Double_precision_floating-point_format
0x1.D6329F1C35CA4 * 2^132 < 1e40 < 0x1.D6329F1C35CA5 * 2^132
i.e. respectively
9999999999999999094860208812374492184576
10000000000000000000000000000000000000000
10000000000000000303786028427003666890752
The exponent (132) is stored as 132+1023 = 1155 = 0x483
And, in fact, the following program prints 483d6329f1c35ca3
(Note the rounding error).
#include <stdio.h>
#include <string.h>
int main(void)
{
int i;
double d = 1.0;
for (i=0; i < 40; ++i) d *= 10.0;
unsigned char buf[8];
memcpy(buf, &d, sizeof buf);
for (i=0; i < 8; ++i) printf("%02x", buf[7-i]);
putchar('\n');
return 0;
}
cf. also
What Every Computer Scientist Should Know About Floating-Point Arithmetic
http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html
Regards.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2011-06-09 09:26 -0700 |
| Message-ID | <lnmxhrc6ot.fsf@nuthaus.mib.org> |
| In reply to | #5686 |
"BartC" <bc@freeuk.com> writes:
> "BartC" <bc@freeuk.com> wrote in message news:isoqbd$i94$1@dont-email.me...
>> Code to convert binary floating point to decimal is very tricky to write.
>> I've just had a go, and while the following sort of works, it's probably
>> full of numerical problems too.
>
> My code introduces errors in the lower bits of the number. I'm trying to
> compare the results to printf(), but if I write:
>
> printf("%f\n",1.0e40);
>
> I get an impossibly clean result of 1 followed by loads of zeros, no matter
> what numbers I stick inside %f. Clearly 1e40 can't be stored exactly (can
> it? I thought it would need over 120 bits of precision), so how can I tell
> printf to show it as it is?
>
> (If I print 1e50, then I've noticed there is a '1' amongst the zeros; that
> can't be right either..)
What implementation are you using?
This program:
#include <stdio.h>
int main(void)
{
printf("%f\n", 1e40);
printf("%f\n", 1e41);
printf("%f\n", 1e42);
printf("%f\n", 1e43);
printf("%f\n", 1e44);
printf("%f\n", 1e45);
printf("%f\n", 1e46);
printf("%f\n", 1e47);
printf("%f\n", 1e48);
printf("%f\n", 1e49);
printf("%f\n", 1e50);
return 0;
}
gives me this output:
10000000000000000303786028427003666890752.000000
100000000000000000620008645040778319495168.000000
1000000000000000044885712678075916785549312.000000
10000000000000000139372116959414099130712064.000000
100000000000000008821361405306422640701865984.000000
999999999999999929757289024535551219930759168.000000
9999999999999999931398190359470212947659194368.000000
100000000000000004384584304507619735463404765184.000000
1000000000000000043845843045076197354634047651840.000000
9999999999999999464902769475481793196872414789632.000000
100000000000000007629769841091887003294964970946560.000000
both on Linux/x86 with gcc and glibc, and on Solaris/SPARC.
(The trailing ".000000" makes sense; for numbers that large, the
only representable values are exact integers.)
If your implementation supports it, you can see the exact values
using "%a" or "%A":
0x1.d6329f1c35ca5p+132
0x1.25dfa371a19e7p+136
0x1.6f578c4e0a061p+139
0x1.cb2d6f618c879p+142
0x1.1efc659cf7d4cp+146
0x1.66bb7f0435c9ep+149
0x1.c06a5ec5433c6p+152
0x1.18427b3b4a05cp+156
0x1.5e531a0a1c873p+159
0x1.b5e7e08ca3a8fp+162
0x1.11b0ec57e649ap+166
--
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"
[toc] | [prev] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2011-06-09 19:07 +0100 |
| Message-ID | <isr26e$l8g$1@dont-email.me> |
| In reply to | #5715 |
"Keith Thompson" <kst-u@mib.org> wrote in message
news:lnmxhrc6ot.fsf@nuthaus.mib.org...
> "BartC" <bc@freeuk.com> writes:
>> printf("%f\n",1.0e40);
>>
>> I get an impossibly clean result of 1 followed by loads of zeros, no
>> matter
>> what numbers I stick inside %f.
> What implementation are you using?
>
> This program:
>
> #include <stdio.h>
> int main(void)
> {
> printf("%f\n", 1e40);
> printf("%f\n", 1e41);
> printf("%f\n", 1e42);
> printf("%f\n", 1e43);
> printf("%f\n", 1e44);
> printf("%f\n", 1e45);
> printf("%f\n", 1e46);
> printf("%f\n", 1e47);
> printf("%f\n", 1e48);
> printf("%f\n", 1e49);
> printf("%f\n", 1e50);
> return 0;
> }
>
> gives me this output:
>
> 10000000000000000303786028427003666890752.000000
(That matches the result in my other post; a good sign..)
> 100000000000000000620008645040778319495168.000000
> 1000000000000000044885712678075916785549312.000000
> 10000000000000000139372116959414099130712064.000000
> 100000000000000008821361405306422640701865984.000000
> 999999999999999929757289024535551219930759168.000000
> 9999999999999999931398190359470212947659194368.000000
> 100000000000000004384584304507619735463404765184.000000
> 1000000000000000043845843045076197354634047651840.000000
> 9999999999999999464902769475481793196872414789632.000000
> 100000000000000007629769841091887003294964970946560.000000
>
> both on Linux/x86 with gcc and glibc, and on Solaris/SPARC.
...
lcc-win32 and gcc (all on x86-32) both give me:
10000000000000000000000000000000000000000.000000
100000000000000000000000000000000000000000.000000
1000000000000000000000000000000000000000000.000000
10000000000000000000000000000000000000000000.000000
100000000000000010000000000000000000000000000.000000
999999999999999930000000000000000000000000000.000000
....
Using DMC, I do get the 303 in the middle of 1e40 for example, but the rest
is still zeros:
10000000000000000303000000000000000000000.000000
Odd. Perhaps some compiler switch is needed?
> (The trailing ".000000" makes sense; for numbers that large, the
> only representable values are exact integers.)
I think it's because you start with an integer (of 52/53 bits for example),
then end up multiplying by a power of two, at least for these bigger
numbers.
> If your implementation supports it, you can see the exact values
> using "%a" or "%A":
>
> 0x1.d6329f1c35ca5p+132
Trouble is I don't 'read' hex; that's why I used a separate program to
extract the bits and build the number.
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2011-06-09 11:52 -0700 |
| Message-ID | <lnaadqdehv.fsf@nuthaus.mib.org> |
| In reply to | #5726 |
"BartC" <bc@freeuk.com> writes:
> "Keith Thompson" <kst-u@mib.org> wrote in message
> news:lnmxhrc6ot.fsf@nuthaus.mib.org...
>> "BartC" <bc@freeuk.com> writes:
>
>>> printf("%f\n",1.0e40);
>>>
>>> I get an impossibly clean result of 1 followed by loads of zeros, no
>>> matter
>>> what numbers I stick inside %f.
>
>> What implementation are you using?
>>
>> This program:
>>
>> #include <stdio.h>
>> int main(void)
>> {
>> printf("%f\n", 1e40);
[...]
>> return 0;
>> }
>>
>> gives me this output:
>>
>> 10000000000000000303786028427003666890752.000000
>
> (That matches the result in my other post; a good sign..)
Oh? You said you got "an impossibly clean result of 1 followed by loads
of zeros"; that doesn't look "impossibly clean" to me.
> lcc-win32 and gcc (all on x86-32) both give me:
>
> 10000000000000000000000000000000000000000.000000
> 100000000000000000000000000000000000000000.000000
> 1000000000000000000000000000000000000000000.000000
> 10000000000000000000000000000000000000000000.000000
> 100000000000000010000000000000000000000000000.000000
> 999999999999999930000000000000000000000000000.000000
> ....
gcc probably isn't relevant; printf is provided by the runtime library,
not by the compiler. For lcc-win32, apparently both are form the same
source, but gcc will use whatever runtime library is on the system.
gcc with glibc on Linux produces the results I posted. gcc on Cygwin
(which I think uses something called "newlib") produces subtly different
results for some values; the Cygwin results are identical for 1e40,
1e41, and 1e42, but have more trailing zeros before the decimal point
for the other values.
glibc seems to be showing the exact stored value, or something
close to it. The results you're getting seem to be the result of
something doing some rounding somewhere.
> Using DMC, I do get the 303 in the middle of 1e40 for example, but the rest
> is still zeros:
>
> 10000000000000000303000000000000000000000.000000
>
> Odd. Perhaps some compiler switch is needed?
Unless a compiler switch affects the behavior of the runtime library
(which is possible), you're probably stuck with the behavior you're
getting unless you change systems.
>> (The trailing ".000000" makes sense; for numbers that large, the
>> only representable values are exact integers.)
>
> I think it's because you start with an integer (of 52/53 bits for example),
> then end up multiplying by a power of two, at least for these bigger
> numbers.
Right.
>> If your implementation supports it, you can see the exact values
>> using "%a" or "%A":
>>
>> 0x1.d6329f1c35ca5p+132
>
> Trouble is I don't 'read' hex; that's why I used a separate program to
> extract the bits and build the number.
...
Ok, here's some new information. Using Perl's Math::BigInt, I've
converted the results (with the trailing ".000000" ignored) to
hexadecimal. The results I got with glibc are:
0x1d6329f1c35ca500000000000000000000
0x125dfa371a19e7000000000000000000000
0xb7abc627050308000000000000000000000
0x72cb5bd86321e40000000000000000000000
0x47bf19673df53000000000000000000000000
0x2cd76fe086b93c000000000000000000000000
0x1c06a5ec5433c60000000000000000000000000
0x118427b3b4a05c00000000000000000000000000
0xaf298d050e439800000000000000000000000000
0x6d79f82328ea3c000000000000000000000000000
0x446c3b15f992680000000000000000000000000000
showing about 53 significant bits followed by zeros, which makes sense.
The results I got on Cygwin are:
0x1d6329f1c35ca500000000000000000000
0x125dfa371a19e7000000000000000000000
0xb7abc627050308000000000000000000000
0x72cb5bd86321e3fffffffffffffffffffffc
0x47bf19673df53000000000000000000000010
0x2cd76fe086b93c000000000000000000000020
0x1c06a5ec5433c5ffffffffffffffffffffffe90
0x118427b3b4a05c00000000000000000000008800
0xaf298d050e439800000000000000000000055000
0x6d79f82328ea3c0000000000000000000000335c0
0x446c3b15f992680000000000000000000001bb5200
which implies some spurious rounding.
Your output of
100000000000000010000000000000000000000000000.000000
is
0x47bf19673df5303cef26e3f42126110000000
which has 118 significant bits.
I'm not suggesting that the implementations you're using are
non-conforming; I don't think printf is required to print more
significant digits than are really there. The standard says "The
value is rounded to the appropriate number of digits."; there may
be some disagreement among implementers about what this means.
My guess is that
100000000000000010000000000000000000000000000.000000
results from computing a rounded result, and then picking up an
insignificant digit in the conversion to a string. I'd probably
call that a bug, but not in the sense that it's non-conforming.
--
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"
[toc] | [prev] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2011-06-09 20:30 +0100 |
| Message-ID | <isr728$mg6$1@dont-email.me> |
| In reply to | #5732 |
"Keith Thompson" <kst-u@mib.org> wrote in message
news:lnaadqdehv.fsf@nuthaus.mib.org...
> "BartC" <bc@freeuk.com> writes:
>> "Keith Thompson" <kst-u@mib.org> wrote in message
>>> printf("%f\n", 1e40);
>>> gives me this output:
>>>
>>> 10000000000000000303786028427003666890752.000000
>>
>> (That matches the result in my other post; a good sign..)
>
> Oh? You said you got "an impossibly clean result of 1 followed by loads
> of zeros"; that doesn't look "impossibly clean" to me.
I meant my reply to James; printf() gives me the clean result, but using
special code to calculate the stored value with bigints gave me the proper
result above.
>> lcc-win32 and gcc (all on x86-32) both give me:
>>
>> 10000000000000000000000000000000000000000.000000
> gcc with glibc on Linux produces the results I posted. gcc on Cygwin
> glibc seems to be showing the exact stored value, or something
> close to it. The results you're getting seem to be the result of
> something doing some rounding somewhere.
>
>> Using DMC, I do get the 303 in the middle of 1e40 for example, but the
>> rest
>> is still zeros:
>>
>> 10000000000000000303000000000000000000000.000000
>>
>> Odd. Perhaps some compiler switch is needed?
>
> Unless a compiler switch affects the behavior of the runtime library
> (which is possible), you're probably stuck with the behavior you're
> getting unless you change systems.
It seems even odder now (if that makes sense...); some implementations will
print the exact result, some will do some internal rounding. And if a
certain precision is specified, it will be ignored if it's beyond some
limit. And it's all a matter of luck.
> Ok, here's some new information. Using Perl's Math::BigInt, I've
> converted the results (with the trailing ".000000" ignored) to
> hexadecimal. The results I got with glibc are:
>
> 0x1d6329f1c35ca500000000000000000000
> showing about 53 significant bits followed by zeros, which makes sense.
>
> The results I got on Cygwin are:
>
> 0x1d6329f1c35ca500000000000000000000
OK, the actual stored value.
> 0x72cb5bd86321e3fffffffffffffffffffffc
> which implies some spurious rounding.
>
> Your output of
> 100000000000000010000000000000000000000000000.000000
> is
> 0x47bf19673df5303cef26e3f42126110000000
> which has 118 significant bits.
>
> I'm not suggesting that the implementations you're using are
> non-conforming; I don't think printf is required to print more
> significant digits than are really there. The standard says "The
> value is rounded to the appropriate number of digits."; there may
> be some disagreement among implementers about what this means.
>
> My guess is that
> 100000000000000010000000000000000000000000000.000000
> results from computing a rounded result, and then picking up an
> insignificant digit in the conversion to a string. I'd probably
> call that a bug, but not in the sense that it's non-conforming.
It doesn't sound right to me. It should be possible to turn off rounding in
order to see exactly what's happening in a calculation,, and one way is by
specifying an extra-large precision. But some libraries apparently don't do
that.
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | "io_x" <a@b.c.invalid> |
|---|---|
| Date | 2011-06-13 12:21 +0200 |
| Message-ID | <4df5e45e$0$13973$4fafbaef@reader2.news.tin.it> |
| In reply to | #5715 |
"Keith Thompson" <kst-u@mib.org> ha scritto nel messaggio
news:lnmxhrc6ot.fsf@nuthaus.mib.org...
> "BartC" <bc@freeuk.com> writes:
>> "BartC" <bc@freeuk.com> wrote in message news:isoqbd$i94$1@dont-email.me...
>>> Code to convert binary floating point to decimal is very tricky to write.
>>> I've just had a go, and while the following sort of works, it's probably
>>> full of numerical problems too.
>>
>> My code introduces errors in the lower bits of the number. I'm trying to
>> compare the results to printf(), but if I write:
>>
>> printf("%f\n",1.0e40);
>>
>> I get an impossibly clean result of 1 followed by loads of zeros, no matter
>> what numbers I stick inside %f. Clearly 1e40 can't be stored exactly (can
>> it? I thought it would need over 120 bits of precision), so how can I tell
>> printf to show it as it is?
>>
>> (If I print 1e50, then I've noticed there is a '1' amongst the zeros; that
>> can't be right either..)
>
> What implementation are you using?
>
> This program:
>
> #include <stdio.h>
> int main(void)
> {
> printf("%f\n", 1e40);
> printf("%f\n", 1e41);
> printf("%f\n", 1e42);
> printf("%f\n", 1e43);
> printf("%f\n", 1e44);
> printf("%f\n", 1e45);
> printf("%f\n", 1e46);
> printf("%f\n", 1e47);
> printf("%f\n", 1e48);
> printf("%f\n", 1e49);
> printf("%f\n", 1e50);
> return 0;
> }
>
> gives me this output:
>
> 10000000000000000303786028427003666890752.000000
> 100000000000000000620008645040778319495168.000000
> 1000000000000000044885712678075916785549312.000000
> 10000000000000000139372116959414099130712064.000000
> 100000000000000008821361405306422640701865984.000000
> 999999999999999929757289024535551219930759168.000000
> 9999999999999999931398190359470212947659194368.000000
> 100000000000000004384584304507619735463404765184.000000
> 1000000000000000043845843045076197354634047651840.000000
> 9999999999999999464902769475481793196872414789632.000000
> 100000000000000007629769841091887003294964970946560.000000
>
> both on Linux/x86 with gcc and glibc, and on Solaris/SPARC.
>
> (The trailing ".000000" makes sense; for numbers that large, the
> only representable values are exact integers.)
>
> If your implementation supports it, you can see the exact values
> using "%a" or "%A":
>
> 0x1.d6329f1c35ca5p+132
> 0x1.25dfa371a19e7p+136
> 0x1.6f578c4e0a061p+139
> 0x1.cb2d6f618c879p+142
> 0x1.1efc659cf7d4cp+146
> 0x1.66bb7f0435c9ep+149
> 0x1.c06a5ec5433c6p+152
> 0x1.18427b3b4a05cp+156
> 0x1.5e531a0a1c873p+159
> 0x1.b5e7e08ca3a8fp+162
> 0x1.11b0ec57e649ap+166
i implement one printf like function named "P";
is this output "printf" conpatible?
int main24(void)
{
P("%f\n", 1e40);
P("%f\n", 1e41);
P("%f\n", 1e42);
P("%f\n", 1e43);
P("%f\n", 1e44);
P("%f\n", 1e45);
P("%f\n", 1e46);
P("%f\n", 1e47);
P("%f\n", 1e48);
P("%f\n", 1e49);
P("%f\n", 1e50);
P("%f\n", 1.4e9);
P("%f\n", 1.4e10);
P("%f\n", 1.4e11);
P("%f\n", 1.4e12);
P("%f\n", 1.4e13);
P("%f\n", 1.4e14);
P("%f\n", 1.4e15);
P("%f\n", 1.4e16);
P("%f\n", 1.4e17);
P("%f\n", 1.4e18);
P("%f\n", 1.4e19);
return 0;
}
the result sound like:
1.000000e40
1.000000e41
1.000000e42
1.000000e43
1.000000e44
1.000000e45
1.000000e46
1.000000e47
1.000000e48
1.000000e49
1.000000e50
1400000000.000000
14000000000.000000
140000000000.00000
1400000000000.0000
i post only now because i found a bug
that print for example
1.0e45
as
10.000000e44
and not as
1.000000e45
the way of print correct result is, for what i think,
ask to assembly programming people how to do
and to hope some "old" people answer
Saluti
[toc] | [prev] | [next] | [standalone]
| From | "io_x" <a@b.c.invalid> |
|---|---|
| Date | 2011-06-13 22:31 +0200 |
| Message-ID | <4df67359$0$2685$4fafbaef@reader1.news.tin.it> |
| In reply to | #5715 |
[alt.lang.asm, comp.lang.c]
"Keith Thompson" ha scritto nel messaggio
news:lnmxhrc6ot.fsf@nuthaus.mib.org...
> "BartC" writes:
>> "BartC" wrote in message news:isoqbd$i94$1@dont-email.me...
>>> Code to convert binary floating point to decimal is very tricky to write.
>>> I've just had a go, and while the following sort of works, it's probably
>>> full of numerical problems too.
>>
>> My code introduces errors in the lower bits of the number. I'm trying to
>> compare the results to printf(), but if I write:
>>
>> printf("%f\n",1.0e40);
>>
>> I get an impossibly clean result of 1 followed by loads of zeros, no matter
>> what numbers I stick inside %f. Clearly 1e40 can't be stored exactly (can
>> it? I thought it would need over 120 bits of precision), so how can I tell
>> printf to show it as it is?
>>
>> (If I print 1e50, then I've noticed there is a '1' amongst the zeros; that
>> can't be right either..)
>
> What implementation are you using?
>
> This program:
>
> #include <stdio.h>
> int main(void)
> {
> printf("%f\n", 1e40);
> printf("%f\n", 1e41);
> printf("%f\n", 1e42);
> printf("%f\n", 1e43);
> printf("%f\n", 1e44);
> printf("%f\n", 1e45);
> printf("%f\n", 1e46);
> printf("%f\n", 1e47);
> printf("%f\n", 1e48);
> printf("%f\n", 1e49);
> printf("%f\n", 1e50);
> return 0;
> }
>
> gives me this output:
>
> 10000000000000000303786028427003666890752.000000
> 100000000000000000620008645040778319495168.000000
> 1000000000000000044885712678075916785549312.000000
> 10000000000000000139372116959414099130712064.000000
> 100000000000000008821361405306422640701865984.000000
> 999999999999999929757289024535551219930759168.000000
> 9999999999999999931398190359470212947659194368.000000
> 100000000000000004384584304507619735463404765184.000000
> 1000000000000000043845843045076197354634047651840.000000
> 9999999999999999464902769475481793196872414789632.000000
> 100000000000000007629769841091887003294964970946560.000000
>
> both on Linux/x86 with gcc and glibc, and on Solaris/SPARC.
>
> (The trailing ".000000" makes sense; for numbers that large, the
> only representable values are exact integers.)
>
> If your implementation supports it, you can see the exact values
> using "%a" or "%A":
>
> 0x1.d6329f1c35ca5p+132
> 0x1.25dfa371a19e7p+136
> 0x1.6f578c4e0a061p+139
> 0x1.cb2d6f618c879p+142
> 0x1.1efc659cf7d4cp+146
> 0x1.66bb7f0435c9ep+149
> 0x1.c06a5ec5433c6p+152
> 0x1.18427b3b4a05cp+156
> 0x1.5e531a0a1c873p+159
> 0x1.b5e7e08ca3a8fp+162
> 0x1.11b0ec57e649ap+166
the "P" function is a function that would print
double 64 bit numbers
someone find one number that not print good?
in below list
thank you
int main24(void)
{P("%.100f\n", -1e-324);
P("%.100f\n", -1e-323);
P("%.100f\n", -1e-300);
P("%.100f\n", -1e-200);
P("%.100f\n", -1e-100);
P("%.100f\n", -1e-80);
P("%.100f\n", -1e-70);
P("%.100f\n", -1e-60);
P("%.100f\n", -1e-50);
P("%.100f\n", -1e-40);
P("%.100f\n", -1e-30);
P("%.100f\n", -1e-20);
P("%.100f\n", -1e-10);
P("%.100f\n", -1e-2);
P("%.100f\n", -1e-1);
P("%.100f\n", -1.0);
P("%.100f\n", -1e1);
P("%.100f\n", -1e2);
P("%.100f\n", -1e4);
P("%.100f\n", -1e10);
P("%.100f\n", -1e11);
P("%.100f\n", -1e12);
P("%.100f\n", -1e13);
P("%.100f\n", -1e14);
P("%.100f\n", -1e15);
P("%.100f\n", -1e16);
P("%.100f\n", -1e17);
P("%.100f\n", -1e18);
P("%.100f\n", -1e19);
P("%.100f\n", -1e30);
P("%.100f\n", -1e50);
P("%.100f\n", -1e70);
P("%.100f\n", -1e90);
P("%.100f\n", -1e100);
P("%.100f\n", -1e120);
P("%.100f\n", -1e140);
P("%.100f\n", -1e160);
P("%.100f\n", -1e180);
P("%.100f\n", -1e200);
P("%.100f\n", -1e308);
P("%.100f\n", -1e309);
P("%.100f\n", 1e-324);
P("%.100f\n", 1e-323);
P("%.100f\n", 1e-300);
P("%.100f\n", 1e-200);
P("%.100f\n", 1e-100);
P("%.100f\n", 1e-80);
P("%.100f\n", 1e-70);
P("%.100f\n", 1e-60);
P("%.100f\n", 1e-50);
P("%.100f\n", 1e-40);
P("%.100f\n", 1e-30);
P("%.100f\n", 1e-20);
P("%.100f\n", 1e-10);
P("%.100f\n", 1e-2);
P("%.100f\n", 1e-1);
P("%.100f\n", 1.0);
P("%.100f\n", 1e1);
P("%.100f\n", 1e2);
P("%.100f\n", 1e4);
P("%.100f\n", 1e10);
P("%.100f\n", 1e11);
P("%.100f\n", 1e12);
P("%.100f\n", 1e13);
P("%.100f\n", 1e14);
P("%.100f\n", 1e15);
P("%.100f\n", 1e16);
P("%.100f\n", 1e17);
P("%.100f\n", 1e18);
P("%.100f\n", 1e19);
P("%.100f\n", 1e30);
P("%.100f\n", 1e50);
P("%.100f\n", 1e70);
P("%.100f\n", 1e90);
P("%.100f\n", 1e100);
P("%.100f\n", 1e120);
P("%.100f\n", 1e140);
P("%.100f\n", 1e160);
P("%.100f\n", 1e180);
P("%.100f\n", 1e200);
P("%.100f\n", 1e308);
P("%.100f\n", 1e309);
return 0;
}
-0.0
-9.8813129168249308e-324
-1.0000000000000000e-300
-9.9999999999999996e-201
-1.0000000000000000e-100
-9.9999999999999997e-81
-1.0000000000000000e-70
-9.9999999999999997e-61
-1.0000000000000000e-50
-9.9999999999999993e-41
-1.0000000000000000e-30
-9.9999999999999994e-21
-0.000000000100000
-0.010000000000000
-0.100000000000000
-1.000000000000000
-10.000000000000000
-100.00000000000000
-10000.000000000000
-10000000000.000000
-100000000000.00000
-1000000000000.0000
-10000000000000.000
-100000000000000.00
-1000000000000000.0
-10000000000000000
-1.0000000000000000e17
-1.0000000000000000e18
-1.0000000000000000e19
-1.0000000000000000e30
-1.0000000000000000e50
-1.0000000000000000e70
-9.9999999999999997e89
-1.0000000000000000e100
-9.9999999999999998e119
-1.0000000000000000e140
-1.0000000000000000e160
-1.0000000000000000e180
-9.9999999999999996e199
-1.0000000000000000e308
-InF
+0.0
9.8813129168249308e-324
1.0000000000000000e-300
9.9999999999999996e-201
1.0000000000000000e-100
9.9999999999999997e-81
1.0000000000000000e-70
9.9999999999999997e-61
1.0000000000000000e-50
9.9999999999999993e-41
1.0000000000000000e-30
9.9999999999999994e-21
0.000000000100000
0.010000000000000
0.100000000000000
1.000000000000000
10.000000000000000
100.00000000000000
10000.000000000000
10000000000.000000
100000000000.00000
1000000000000.0000
10000000000000.000
100000000000000.00
1000000000000000.0
10000000000000000
1.0000000000000000e17
1.0000000000000000e18
1.0000000000000000e19
1.0000000000000000e30
1.0000000000000000e50
1.0000000000000000e70
9.9999999999999997e89
1.0000000000000000e100
9.9999999999999998e119
1.0000000000000000e140
1.0000000000000000e160
1.0000000000000000e180
9.9999999999999996e199
1.0000000000000000e308
+InF
[toc] | [prev] | [next] | [standalone]
| From | Noob <root@127.0.0.1> |
|---|---|
| Date | 2011-06-10 10:58 +0200 |
| Message-ID | <issmar$fed$1@dont-email.me> |
| In reply to | #5686 |
[ Re-posting through E-S, as aioe seems heavily filtered ]
OT: How many see this post, and not the one through aioe?
BartC wrote:
> Clearly 1e40 can't be stored exactly (can it?
> I thought it would need over 120 bits of precision)
1e40 = 10^40
= 5^40 * 2^40
= 0x1D6329F1C35CA4BFABB9F561 * 2^40
5^40 requires 93 bits to store precisely.
Thus, a double-precision IEEE 754 floating-point number
cannot store 1e40 exactly, as the mantissa is expressed
over (only) 52 bits.
http://en.wikipedia.org/wiki/Double_precision_floating-point_format
0x1.D6329F1C35CA4 * 2^132 < 1e40 < 0x1.D6329F1C35CA5 * 2^132
i.e. respectively
9999999999999999094860208812374492184576
10000000000000000000000000000000000000000
10000000000000000303786028427003666890752
The exponent (132) is stored as 132+1023 = 1155 = 0x483
And, in fact, the following program prints 483d6329f1c35ca3
(Note the rounding error).
#include <stdio.h>
#include <string.h>
int main(void)
{
int i;
double d = 1.0;
for (i=0; i < 40; ++i) d *= 10.0;
unsigned char buf[8];
memcpy(buf, &d, sizeof buf);
for (i=0; i < 8; ++i) printf("%02x", buf[7-i]);
putchar('\n');
return 0;
}
cf. also
What Every Computer Scientist Should Know About Floating-Point Arithmetic
http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html
Regards.
[toc] | [prev] | [next] | [standalone]
| From | Seebs <usenet-nospam@seebs.net> |
|---|---|
| Date | 2011-06-10 22:49 +0000 |
| Message-ID | <slrniv4tv8.1shu.usenet-nospam@guild.seebs.net> |
| In reply to | #5783 |
On 2011-06-10, Noob <root@127.0.0.1> wrote: > [ Re-posting through E-S, as aioe seems heavily filtered ] > OT: How many see this post, and not the one through aioe? Me. I filter aioe because such a large number of the recurring trolls of this group seem to use it for their socks. > cf. also > What Every Computer Scientist Should Know About Floating-Point Arithmetic I think I see that recommended, on average, about twice a week. I think I read it once, but either a very long time ago or not actually at all. Gonna go do that now. -s -- Copyright 2011, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated! I am not speaking for my employer, although they do rent some of my opinions.
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.c
csiph-web