9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* Re: [9fans] fun and scary evil C code
@ 2007-12-20 16:29 Russ Cox
  0 siblings, 0 replies; 11+ messages in thread
From: Russ Cox @ 2007-12-20 16:29 UTC (permalink / raw)
  To: 9fans

> Does C99 or any other C mandate the actual memory layout
> of floats and doubles or the exact conversion of constant  
> representations?
> I'm fairly sure they somehow mandate IEEE 754 properties,
> but do they actually say that floats and doubles have to be stored  
> exactly that way in 4 or 8 bytes?
> 
> Even if we assume sizeof(double) == 8,
> what if my implementation is perverse and interleaves the exponent  
> bits amongst the mantissa bits?
> Where is this disallowed in the standard(s)?

It doesn't matter what the standard says; it matters what implementations do.
C implementations are going to provide what the underlying
hardware does, and almost all hardware does IEEE 754.

> as long as the conversion you're after has an exact ieee representation,
> i can't see how two compliant implementations could come up with
> differing representations.  (two different numbers can't have the same
> ieee representation, except -0 and +0.)  the conversion process doesn't
> need any floating point itself and the only interpolation comes when
> numbers don't have exact representations.

Historically, it has not always been true that decimal <-> binary
conversion of doubles has been precise enough to replicate a 
specific bit pattern.  While conversion doesn't require floating
point, it is often done in floating point anyway for convenience.

Russ


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [9fans] fun and scary evil C code
  2007-12-20  9:29         ` roger peppe
@ 2007-12-20 13:02           ` erik quanstrom
  0 siblings, 0 replies; 11+ messages in thread
From: erik quanstrom @ 2007-12-20 13:02 UTC (permalink / raw)
  To: 9fans

as long as the conversion you're after has an exact ieee representation,
i can't see how two compliant implementations could come up with
differing representations.  (two different numbers can't have the same
ieee representation, except -0 and +0.)  the conversion process doesn't
need any floating point itself and the only interpolation comes when
numbers don't have exact representations.

it didn't occur to me immediately after russ' post that what he said
was literally correct:

#include<u.h>
#include<libc.h>

#define Magici(x) (((uchar*)&magic)[7-(x)])
static double magic = 7.949928895127363e-275;

void
main(void)
{
	uint sign, exp;
	uvlong sig, *v;

	v = (uvlong*)&magic;
	sign = *v>>63;
	exp = *v>>52;
	sig = *v&~(4096-1LL<<52);
	print("%b*%b*%ullx\n", sign, exp, sig);
	print("%ullx\n", *v);
}

- erik


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [9fans] fun and scary evil C code
  2007-12-20  0:51       ` erik quanstrom
@ 2007-12-20  9:29         ` roger peppe
  2007-12-20 13:02           ` erik quanstrom
  0 siblings, 1 reply; 11+ messages in thread
From: roger peppe @ 2007-12-20  9:29 UTC (permalink / raw)
  To: Fans of the OS Plan 9 from Bell Labs

On Dec 20, 2007 12:51 AM, erik quanstrom <quanstro@quanstro.net> wrote:
> in any event, if ieee is used, i think the trick is safe.

surely it depends crucially on the consistency of the decimal to float
conversion?
is that standard?


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [9fans] fun and scary evil C code
  2007-12-20  0:33     ` dave.l
@ 2007-12-20  0:51       ` erik quanstrom
  2007-12-20  9:29         ` roger peppe
  0 siblings, 1 reply; 11+ messages in thread
From: erik quanstrom @ 2007-12-20  0:51 UTC (permalink / raw)
  To: 9fans

> I lied.
> They're actually using that stuff to pick apart the (presumed IEEE 754)
> doubles into exponent, mantissa, ...
> 
> My questions still stand ...
> 
> Also, that file is such a tangled nest of ifdefs ...
> is anyone sure whether (and if so, when) that code is invoked?

interesting conflicts on the web.  http://en.wikipedia.org/wiki/IEEE_754
says c doesn't require ieee, http://home.datacomm.ch/t_wolf/tw/c/c9x_changes.html point #21.
says it does.

in any event, if ieee is used, i think the trick is safe.

- erik


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [9fans] fun and scary evil C code
  2007-12-20  0:18   ` dave.l
@ 2007-12-20  0:33     ` dave.l
  2007-12-20  0:51       ` erik quanstrom
  0 siblings, 1 reply; 11+ messages in thread
From: dave.l @ 2007-12-20  0:33 UTC (permalink / raw)
  To: Fans of the OS Plan 9 from Bell Labs

> As far as I can see,
> they're assuming that double is IEEE 754 and that you can
> rip apart such a representation on an random-endian machine
> and re-assemble it on an any other random-endian machine.

I lied.
They're actually using that stuff to pick apart the (presumed IEEE 754)
doubles into exponent, mantissa, ...

My questions still stand ...

Also, that file is such a tangled nest of ifdefs ...
is anyone sure whether (and if so, when) that code is invoked?

DaveL


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [9fans] fun and scary evil C code
  2007-12-19 20:37 ` Russ Cox
  2007-12-19 22:32   ` Robert William Fuller
  2007-12-19 22:51   ` Bakul Shah
@ 2007-12-20  0:18   ` dave.l
  2007-12-20  0:33     ` dave.l
  2 siblings, 1 reply; 11+ messages in thread
From: dave.l @ 2007-12-20  0:18 UTC (permalink / raw)
  To: Fans of the OS Plan 9 from Bell Labs

> there, of course, we have a real compiler and don't have to
> write uvlong constants as floating point numbers
> (wow that seems fragile).

Scarily: they're not:
if you read on, that macro is for picking apart a double into bytes  
and vice-versa.
(i.e. it's insanity is internally consistent).
It's still ludicrous and fragile.

As far as I can see,
they're assuming that double is IEEE 754 and that you can
rip apart such a representation on an random-endian machine
and re-assemble it on an any other random-endian machine.

Does C99 or any other C mandate the actual memory layout
of floats and doubles or the exact conversion of constant  
representations?
I'm fairly sure they somehow mandate IEEE 754 properties,
but do they actually say that floats and doubles have to be stored  
exactly that way in 4 or 8 bytes?

Even if we assume sizeof(double) == 8,
what if my implementation is perverse and interleaves the exponent  
bits amongst the mantissa bits?
Where is this disallowed in the standard(s)?

DaveL




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [9fans] fun and scary evil C code
  2007-12-19 20:37 ` Russ Cox
  2007-12-19 22:32   ` Robert William Fuller
@ 2007-12-19 22:51   ` Bakul Shah
  2007-12-20  0:18   ` dave.l
  2 siblings, 0 replies; 11+ messages in thread
From: Bakul Shah @ 2007-12-19 22:51 UTC (permalink / raw)
  To: Fans of the OS Plan 9 from Bell Labs

> > #define TRIO_DOUBLE_INDEX(x) (((unsigned char *)&internalEndianMagic)[7-(x)
> ])
> 
> this is actually done in /sys/src/9/port/devcons.c too:
> 
> 	static uvlong uvorder = 0x0001020304050607ULL;
> 	
> 	static uchar*
> 	le2vlong(vlong *to, uchar *f)
> 	{
> 		uchar *t, *o;
> 		int i;
> 	
> 		t = (uchar*)to;
> 		o = (uchar*)&uvorder;
> 		for(i = 0; i < sizeof(vlong); i++)
> 			t[o[i]] = f[i];
> 		return f+sizeof(vlong);
> 	}
> 	
> 	static uchar*
> 	vlong2le(uchar *t, vlong from)
> 	{
> 		uchar *f, *o;
> 		int i;
> 	
> 		f = (uchar*)&from;
> 		o = (uchar*)&uvorder;
> 		for(i = 0; i < sizeof(vlong); i++)
> 			t[i] = f[o[i]];
> 		return t+sizeof(vlong);
> 	}
> 
> presotto wrote the code but said he learned the trick from ken.
> 
> there, of course, we have a real compiler and don't have to
> write uvlong constants as floating point numbers
> (wow that seems fragile).

Most likely the TRIO_DOUBLE_INDEX macro came from some code
from the pre-long-long days, when you had no other way to
write down an 8 byte value in host endian order (even in a
less than portable way).


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [9fans] fun and scary evil C code
  2007-12-19 22:32   ` Robert William Fuller
@ 2007-12-19 22:38     ` erik quanstrom
  0 siblings, 0 replies; 11+ messages in thread
From: erik quanstrom @ 2007-12-19 22:38 UTC (permalink / raw)
  To: 9fans

> > presotto wrote the code but said he learned the trick from ken.
> > 
> > there, of course, we have a real compiler and don't have to
> > write uvlong constants as floating point numbers
> > (wow that seems fragile).
> > 
> > russ
> 
> Now THAT's something to be proud of.  Especially without comments.

which.  writing the code or learning tricks from ken?

☺

- erik


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [9fans] fun and scary evil C code
  2007-12-19 20:37 ` Russ Cox
@ 2007-12-19 22:32   ` Robert William Fuller
  2007-12-19 22:38     ` erik quanstrom
  2007-12-19 22:51   ` Bakul Shah
  2007-12-20  0:18   ` dave.l
  2 siblings, 1 reply; 11+ messages in thread
From: Robert William Fuller @ 2007-12-19 22:32 UTC (permalink / raw)
  To: Fans of the OS Plan 9 from Bell Labs

Russ Cox wrote:
>> #define TRIO_DOUBLE_INDEX(x) (((unsigned char *)&internalEndianMagic)[7-(x)])
> 
> this is actually done in /sys/src/9/port/devcons.c too:
> 
> 	static uvlong uvorder = 0x0001020304050607ULL;
> 	
> 	static uchar*
> 	le2vlong(vlong *to, uchar *f)
> 	{
> 		uchar *t, *o;
> 		int i;
> 	
> 		t = (uchar*)to;
> 		o = (uchar*)&uvorder;
> 		for(i = 0; i < sizeof(vlong); i++)
> 			t[o[i]] = f[i];
> 		return f+sizeof(vlong);
> 	}
> 	
> 	static uchar*
> 	vlong2le(uchar *t, vlong from)
> 	{
> 		uchar *f, *o;
> 		int i;
> 	
> 		f = (uchar*)&from;
> 		o = (uchar*)&uvorder;
> 		for(i = 0; i < sizeof(vlong); i++)
> 			t[i] = f[o[i]];
> 		return t+sizeof(vlong);
> 	}
> 
> presotto wrote the code but said he learned the trick from ken.
> 
> there, of course, we have a real compiler and don't have to
> write uvlong constants as floating point numbers
> (wow that seems fragile).
> 
> russ

Now THAT's something to be proud of.  Especially without comments.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [9fans] fun and scary evil C code
  2007-12-19 15:15 David Leimbach
@ 2007-12-19 20:37 ` Russ Cox
  2007-12-19 22:32   ` Robert William Fuller
                     ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Russ Cox @ 2007-12-19 20:37 UTC (permalink / raw)
  To: 9fans

> #define TRIO_DOUBLE_INDEX(x) (((unsigned char *)&internalEndianMagic)[7-(x)])

this is actually done in /sys/src/9/port/devcons.c too:

	static uvlong uvorder = 0x0001020304050607ULL;
	
	static uchar*
	le2vlong(vlong *to, uchar *f)
	{
		uchar *t, *o;
		int i;
	
		t = (uchar*)to;
		o = (uchar*)&uvorder;
		for(i = 0; i < sizeof(vlong); i++)
			t[o[i]] = f[i];
		return f+sizeof(vlong);
	}
	
	static uchar*
	vlong2le(uchar *t, vlong from)
	{
		uchar *f, *o;
		int i;
	
		f = (uchar*)&from;
		o = (uchar*)&uvorder;
		for(i = 0; i < sizeof(vlong); i++)
			t[i] = f[o[i]];
		return t+sizeof(vlong);
	}

presotto wrote the code but said he learned the trick from ken.

there, of course, we have a real compiler and don't have to
write uvlong constants as floating point numbers
(wow that seems fragile).

russ


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [9fans] fun and scary evil C code
@ 2007-12-19 15:15 David Leimbach
  2007-12-19 20:37 ` Russ Cox
  0 siblings, 1 reply; 11+ messages in thread
From: David Leimbach @ 2007-12-19 15:15 UTC (permalink / raw)
  To: 9fans

[-- Attachment #1: Type: text/plain, Size: 1037 bytes --]

I was amused by this:
http://www.steike.com/code/useless/evil-c/

I particularly liked the "internalEndianMagic".

I see this in some XML libs, as well as GMP and other open sourced code.

http://unix.derkeiler.com/Newsgroups/comp.unix.programmer/2005-12/msg00198.html


From:
https://svn.r-project.org/R/trunk/src/extra/trio/trionan.c

/*
 * Endian-agnostic indexing macro.
 *
 * The value of internalEndianMagic, when converted into a 64-bit
 * integer, becomes 0x0706050403020100 (we could have used a 64-bit
 * integer value instead of a double, but not all platforms supports
 * that type). The value is automatically encoded with the correct
 * endianess by the compiler, which means that we can support any
 * kind of endianess. The individual bytes are then used as an index
 * for the IEEE 754 bit-patterns and masks.
 */
#define TRIO_DOUBLE_INDEX(x) (((unsigned char *)&internalEndianMagic)[7-(x)])
static TRIO_CONST double internalEndianMagic = 7.949928895127363e-275;
#endif

pretty weird stuff.

[-- Attachment #2: Type: text/html, Size: 2084 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2007-12-20 16:29 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-12-20 16:29 [9fans] fun and scary evil C code Russ Cox
  -- strict thread matches above, loose matches on Subject: below --
2007-12-19 15:15 David Leimbach
2007-12-19 20:37 ` Russ Cox
2007-12-19 22:32   ` Robert William Fuller
2007-12-19 22:38     ` erik quanstrom
2007-12-19 22:51   ` Bakul Shah
2007-12-20  0:18   ` dave.l
2007-12-20  0:33     ` dave.l
2007-12-20  0:51       ` erik quanstrom
2007-12-20  9:29         ` roger peppe
2007-12-20 13:02           ` erik quanstrom

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).