|  | // Copyright 2009 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | #include "runtime.h" | 
|  |  | 
|  | static	uint64	uvnan		= 0x7FF0000000000001ULL; | 
|  | static	uint64	uvinf		= 0x7FF0000000000000ULL; | 
|  | static	uint64	uvneginf	= 0xFFF0000000000000ULL; | 
|  |  | 
|  | uint32 | 
|  | float32tobits(float32 f) | 
|  | { | 
|  | // The obvious cast-and-pointer code is technically | 
|  | // not valid, and gcc miscompiles it.  Use a union instead. | 
|  | union { | 
|  | float32 f; | 
|  | uint32 i; | 
|  | } u; | 
|  | u.f = f; | 
|  | return u.i; | 
|  | } | 
|  |  | 
|  | uint64 | 
|  | float64tobits(float64 f) | 
|  | { | 
|  | // The obvious cast-and-pointer code is technically | 
|  | // not valid, and gcc miscompiles it.  Use a union instead. | 
|  | union { | 
|  | float64 f; | 
|  | uint64 i; | 
|  | } u; | 
|  | u.f = f; | 
|  | return u.i; | 
|  | } | 
|  |  | 
|  | float64 | 
|  | float64frombits(uint64 i) | 
|  | { | 
|  | // The obvious cast-and-pointer code is technically | 
|  | // not valid, and gcc miscompiles it.  Use a union instead. | 
|  | union { | 
|  | float64 f; | 
|  | uint64 i; | 
|  | } u; | 
|  | u.i = i; | 
|  | return u.f; | 
|  | } | 
|  |  | 
|  | float32 | 
|  | float32frombits(uint32 i) | 
|  | { | 
|  | // The obvious cast-and-pointer code is technically | 
|  | // not valid, and gcc miscompiles it.  Use a union instead. | 
|  | union { | 
|  | float32 f; | 
|  | uint32 i; | 
|  | } u; | 
|  | u.i = i; | 
|  | return u.f; | 
|  | } | 
|  |  | 
|  | bool | 
|  | isInf(float64 f, int32 sign) | 
|  | { | 
|  | uint64 x; | 
|  |  | 
|  | x = float64tobits(f); | 
|  | if(sign == 0) | 
|  | return x == uvinf || x == uvneginf; | 
|  | if(sign > 0) | 
|  | return x == uvinf; | 
|  | return x == uvneginf; | 
|  | } | 
|  |  | 
|  | float64 | 
|  | NaN(void) | 
|  | { | 
|  | return float64frombits(uvnan); | 
|  | } | 
|  |  | 
|  | bool | 
|  | isNaN(float64 f) | 
|  | { | 
|  | uint64 x; | 
|  |  | 
|  | x = float64tobits(f); | 
|  | return ((uint32)(x>>52) & 0x7FF) == 0x7FF && !isInf(f, 0); | 
|  | } | 
|  |  | 
|  | float64 | 
|  | Inf(int32 sign) | 
|  | { | 
|  | if(sign >= 0) | 
|  | return float64frombits(uvinf); | 
|  | else | 
|  | return float64frombits(uvneginf); | 
|  | } | 
|  |  | 
|  | enum | 
|  | { | 
|  | MASK	= 0x7ffL, | 
|  | SHIFT	= 64-11-1, | 
|  | BIAS	= 1022L, | 
|  | }; | 
|  |  | 
|  | float64 | 
|  | frexp(float64 d, int32 *ep) | 
|  | { | 
|  | uint64 x; | 
|  |  | 
|  | if(d == 0) { | 
|  | *ep = 0; | 
|  | return 0; | 
|  | } | 
|  | x = float64tobits(d); | 
|  | *ep = (int32)((x >> SHIFT) & MASK) - BIAS; | 
|  | x &= ~((uint64)MASK << SHIFT); | 
|  | x |= (uint64)BIAS << SHIFT; | 
|  | return float64frombits(x); | 
|  | } | 
|  |  | 
|  | float64 | 
|  | ldexp(float64 d, int32 e) | 
|  | { | 
|  | uint64 x; | 
|  |  | 
|  | if(d == 0) | 
|  | return 0; | 
|  | x = float64tobits(d); | 
|  | e += (int32)(x >> SHIFT) & MASK; | 
|  | if(e <= 0) | 
|  | return 0;	/* underflow */ | 
|  | if(e >= MASK){		/* overflow */ | 
|  | if(d < 0) | 
|  | return Inf(-1); | 
|  | return Inf(1); | 
|  | } | 
|  | x &= ~((uint64)MASK << SHIFT); | 
|  | x |= (uint64)e << SHIFT; | 
|  | return float64frombits(x); | 
|  | } | 
|  |  | 
|  | float64 | 
|  | modf(float64 d, float64 *ip) | 
|  | { | 
|  | float64 dd; | 
|  | uint64 x; | 
|  | int32 e; | 
|  |  | 
|  | if(d < 1) { | 
|  | if(d < 0) { | 
|  | d = modf(-d, ip); | 
|  | *ip = -*ip; | 
|  | return -d; | 
|  | } | 
|  | *ip = 0; | 
|  | return d; | 
|  | } | 
|  |  | 
|  | x = float64tobits(d); | 
|  | e = (int32)((x >> SHIFT) & MASK) - BIAS; | 
|  |  | 
|  | /* | 
|  | * Keep the top 11+e bits; clear the rest. | 
|  | */ | 
|  | if(e <= 64-11) | 
|  | x &= ~(((uint64)1 << (64LL-11LL-e))-1); | 
|  | dd = float64frombits(x); | 
|  | *ip = dd; | 
|  | return d - dd; | 
|  | } | 
|  |  |