/* This module provides declarations and definitions common to the
implementations of C standard math functions nanf, nan, and nanl in nan.c
and nanl.c.
$Revision: 1.4 $, $Date: 2006/02/01 18:36:35 $
*/
/*
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/* These definitions and the implementations of nanf, nan, and nanl rely on:
The C 1999 standard, ISO/IEC 9899:1999(E), Programming Languages--C.
IEEE Std 754-1985, IEEE Standard for Binary Floating-Point Arithmetic.
(Later designated IEC 60559 and IEC 559.)
GCC behavior:
__BIG_ENDIAN__ is defined iff the most significant bytes of an
object appear at lower addresses.
Data may be written to one member of a union and read with a new
interpretation from another member.
In the run-time character set, the digits 0 through 9 must be
consecutive characters, the letters A through F must be consecutive
characters, and the letters a through f must be consecutive
characters.
__POWERPC__ and __i386__ are defined when compiling for the
corresponding architectures.
__LONG_DOUBLE_128__ is defined iff long double is implemented as
pair of doubles.
PowerPC and Intel IA-32 architecture:
The floating-point format, including that the most significant bit
of the significand of a NaN is true iff the NaN is quiet.
Motorola (later separated into Freescale), Programming
Environments Manual for 32-Bit Implementations of the PowerPC
Architecture, MPCFPE32B/AD 12/2002 Revision 2, section 3.3,
"Floating-Point Execution Models--UISA."
Intel, IA-32 Intel Architecture Software Developer's Manual,
Volume 1: Basic Architecture, 2002, 245470-007, section 4.8,
"Real Numbers and Floating-Point Formats."
*/
#include "math.h"
#include
#include
// Define the type Float to access the representation of a float.
typedef union
{
float f;
struct
{
#if defined __BIG_ENDIAN__
unsigned int sign : 1;
unsigned int exponent : 8;
unsigned int quiet : 1;
unsigned int significand : 22;
#else
unsigned int significand : 22;
unsigned int quiet : 1;
unsigned int exponent : 8;
unsigned int sign : 1;
#endif
} s;
} Float;
// Define the type Double to access the representation of a double.
typedef union
{
double d;
struct
{
#if defined __BIG_ENDIAN__
unsigned int sign : 1;
unsigned int exponent : 11;
unsigned int quiet : 1;
uint64_t significand : 51;
#else
uint64_t significand : 51;
unsigned int quiet : 1;
unsigned int exponent : 11;
unsigned int sign : 1;
#endif
} s;
} Double;
/* Define the type LongDouble to access the representation of a long double.
This has some complications. On a PowerPC, a long double is implemented
either as two doubles (with -mlong-double-128, the default) or as a single
double (with -mlong-double-64, provided primarily for Unix 2003
compliance). In a long double NaN, the value of the second double, if
present, is ignored. Only the significand of the first double is used.
On IA-32, a long double has a different format, with an explicit integer
bit in the significand.
We mostly handle these differences in this type definition. The nanl code
has some additional code that is conditional on the differences.
It is probably overkill to provide both big- and little-endian definitions
for each of PowerPC and IA-32, but it does not hurt to be prepared.
*/
typedef union
{
long double ld;
#if defined __POWERPC__ // Architecture.
struct
{
#if defined __BIG_ENDIAN__
unsigned int sign : 1;
unsigned int exponent : 11;
unsigned int quiet : 1;
uint64_t significand : 51;
#if defined __LONG_DOUBLE_128__
double d;
#endif
#else
#if defined __LONG_DOUBLE_128__
double d;
#endif
uint64_t significand : 51;
unsigned int quiet : 1;
unsigned int exponent : 11;
unsigned int sign : 1;
#endif
} s;
#elif ( defined( __i386__ ) || defined( __x86_64__ ) ) // Architecture.
struct
{
#if defined __BIG_ENDIAN__
unsigned int sign : 1;
unsigned int exponent : 15;
unsigned int integer : 1;
unsigned int quiet : 1;
uint64_t significand : 62;
#else
uint64_t significand : 62;
unsigned int quiet : 1;
unsigned int integer : 1;
unsigned int exponent : 15;
unsigned int sign : 1;
#endif
} __attribute__((packed)) s;
#else // Architecture.
// Code for long doubles must be written for this architecture.
#error "Unrecognized architecture."
#endif // Architecture.
} LongDouble;
/* ConstructSignificand parses the tagp argument of nanf, nan, or nanl and
returns a 64-bit number that should be placed into the significand of the
NaN being returned.
(This returns the low 64 bits of the number represented by the numeral in
tagp, and the appropriate number of low bits should be copied into the
NaN.)
If tagp does not consist of a recognized numeral, zero is returned.
*/
static uint_least64_t ConstructSignificand(const char *tagp)
{
if (tagp == NULL)
return 0;
// Determine the numeral base from the leading characters.
if (*tagp == '0')
{
++tagp; // Consume the zero.
if (*tagp == 'x' || *tagp == 'X')
{
++tagp; // Consume the x.
/* "0x" or "0X" indicates hexadecimal.
For each hexadecimal digit, shift the significand left and
insert the new digit on the right. If any character other
than a hexadecimal digit is encountered, return zero.
Observe that "0x" is accepted as a hexadecimal numeral, but it
returns 0, the same value we use for rejected strings. If the
value returned for rejected strings changes, the code here has
to check whether there is at least one digit.
*/
char c;
uint_least64_t significand = 0;
while (c = *tagp++)
if ('0' <= c && c <= '9')
significand = significand<<4 | c - '0';
else if ('a' <= c && c <= 'f')
significand = significand<<4 | c - 'a' + 0xa;
else if ('A' <= c && c <= 'F')
significand = significand<<4 | c - 'A' + 0xa;
else
return 0;
return significand;
}
else
{
/* "0" without "x" or "X" indicates octal.
For each octal digit, shift the significand left and insert the
new digit on the right. If any character other than an octal
digit is encountered, return zero.
*/
char c;
uint_least64_t significand = 0;
while (c = *tagp++)
if ('0' <= c && c <= '7')
significand = significand<<3 | c - '0';
else
return 0;
return significand;
}
}
else
{
/* For each decimal digit, multiply the value by ten and add the
new digit. If any character other than a decimal digit is
encountered, return zero.
*/
char c;
uint_least64_t significand = 0;
while (c = *tagp++)
if ('0' <= c && c <= '9')
significand = significand*10 + c - '0';
else
return 0;
return significand;
}
}