/*	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.3 $, $Date: 2005/06/23 18:26:55 $
*/


/*
 * 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 <stdint.h>
#include <stdlib.h>


// 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__		// 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;
	}
}
