Blame Half/half.cpp

Packit 8dc392
///////////////////////////////////////////////////////////////////////////
Packit 8dc392
//
Packit 8dc392
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
Packit 8dc392
// Digital Ltd. LLC
Packit 8dc392
// 
Packit 8dc392
// All rights reserved.
Packit 8dc392
// 
Packit 8dc392
// Redistribution and use in source and binary forms, with or without
Packit 8dc392
// modification, are permitted provided that the following conditions are
Packit 8dc392
// met:
Packit 8dc392
// *       Redistributions of source code must retain the above copyright
Packit 8dc392
// notice, this list of conditions and the following disclaimer.
Packit 8dc392
// *       Redistributions in binary form must reproduce the above
Packit 8dc392
// copyright notice, this list of conditions and the following disclaimer
Packit 8dc392
// in the documentation and/or other materials provided with the
Packit 8dc392
// distribution.
Packit 8dc392
// *       Neither the name of Industrial Light & Magic nor the names of
Packit 8dc392
// its contributors may be used to endorse or promote products derived
Packit 8dc392
// from this software without specific prior written permission. 
Packit 8dc392
// 
Packit 8dc392
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 8dc392
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 8dc392
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 8dc392
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 8dc392
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 8dc392
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 8dc392
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 8dc392
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 8dc392
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 8dc392
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 8dc392
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 8dc392
//
Packit 8dc392
///////////////////////////////////////////////////////////////////////////
Packit 8dc392
Packit 8dc392
// Primary authors:
Packit 8dc392
//     Florian Kainz <kainz@ilm.com>
Packit 8dc392
//     Rod Bogart <rgb@ilm.com>
Packit 8dc392
Packit 8dc392
Packit 8dc392
//---------------------------------------------------------------------------
Packit 8dc392
//
Packit 8dc392
//	class half --
Packit 8dc392
//	implementation of non-inline members
Packit 8dc392
//
Packit 8dc392
//---------------------------------------------------------------------------
Packit 8dc392
Packit 8dc392
#include <assert.h>
Packit 8dc392
#include "half.h"
Packit 8dc392
Packit 8dc392
using namespace std;
Packit 8dc392
Packit 8dc392
//-------------------------------------------------------------
Packit 8dc392
// Lookup tables for half-to-float and float-to-half conversion
Packit 8dc392
//-------------------------------------------------------------
Packit 8dc392
Packit 8dc392
HALF_EXPORT const half::uif half::_toFloat[1 << 16] =
Packit 8dc392
    #include "toFloat.h"
Packit 8dc392
HALF_EXPORT const unsigned short half::_eLut[1 << 9] =
Packit 8dc392
    #include "eLut.h"
Packit 8dc392
Packit 8dc392
//-----------------------------------------------
Packit 8dc392
// Overflow handler for float-to-half conversion;
Packit 8dc392
// generates a hardware floating-point overflow,
Packit 8dc392
// which may be trapped by the operating system.
Packit 8dc392
//-----------------------------------------------
Packit 8dc392
Packit 8dc392
HALF_EXPORT float
Packit 8dc392
half::overflow ()
Packit 8dc392
{
Packit 8dc392
    volatile float f = 1e10;
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 10; i++)	
Packit 8dc392
	f *= f;				// this will overflow before
Packit 8dc392
					// the for­loop terminates
Packit 8dc392
    return f;
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
//-----------------------------------------------------
Packit 8dc392
// Float-to-half conversion -- general case, including
Packit 8dc392
// zeroes, denormalized numbers and exponent overflows.
Packit 8dc392
//-----------------------------------------------------
Packit 8dc392
Packit 8dc392
HALF_EXPORT short
Packit 8dc392
half::convert (int i)
Packit 8dc392
{
Packit 8dc392
    //
Packit 8dc392
    // Our floating point number, f, is represented by the bit
Packit 8dc392
    // pattern in integer i.  Disassemble that bit pattern into
Packit 8dc392
    // the sign, s, the exponent, e, and the significand, m.
Packit 8dc392
    // Shift s into the position where it will go in in the
Packit 8dc392
    // resulting half number.
Packit 8dc392
    // Adjust e, accounting for the different exponent bias
Packit 8dc392
    // of float and half (127 versus 15).
Packit 8dc392
    //
Packit 8dc392
Packit 8dc392
    register int s =  (i >> 16) & 0x00008000;
Packit 8dc392
    register int e = ((i >> 23) & 0x000000ff) - (127 - 15);
Packit 8dc392
    register int m =   i        & 0x007fffff;
Packit 8dc392
Packit 8dc392
    //
Packit 8dc392
    // Now reassemble s, e and m into a half:
Packit 8dc392
    //
Packit 8dc392
Packit 8dc392
    if (e <= 0)
Packit 8dc392
    {
Packit 8dc392
	if (e < -10)
Packit 8dc392
	{
Packit 8dc392
	    //
Packit 8dc392
	    // E is less than -10.  The absolute value of f is
Packit 8dc392
	    // less than HALF_MIN (f may be a small normalized
Packit 8dc392
	    // float, a denormalized float or a zero).
Packit 8dc392
	    //
Packit 8dc392
	    // We convert f to a half zero with the same sign as f.
Packit 8dc392
	    //
Packit 8dc392
Packit 8dc392
	    return s;
Packit 8dc392
	}
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// E is between -10 and 0.  F is a normalized float
Packit 8dc392
	// whose magnitude is less than HALF_NRM_MIN.
Packit 8dc392
	//
Packit 8dc392
	// We convert f to a denormalized half.
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Add an explicit leading 1 to the significand.
Packit 8dc392
	// 
Packit 8dc392
Packit 8dc392
	m = m | 0x00800000;
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Round to m to the nearest (10+e)-bit value (with e between
Packit 8dc392
	// -10 and 0); in case of a tie, round to the nearest even value.
Packit 8dc392
	//
Packit 8dc392
	// Rounding may cause the significand to overflow and make
Packit 8dc392
	// our number normalized.  Because of the way a half's bits
Packit 8dc392
	// are laid out, we don't have to treat this case separately;
Packit 8dc392
	// the code below will handle it correctly.
Packit 8dc392
	// 
Packit 8dc392
Packit 8dc392
	int t = 14 - e;
Packit 8dc392
	int a = (1 << (t - 1)) - 1;
Packit 8dc392
	int b = (m >> t) & 1;
Packit 8dc392
Packit 8dc392
	m = (m + a + b) >> t;
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Assemble the half from s, e (zero) and m.
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	return s | m;
Packit 8dc392
    }
Packit 8dc392
    else if (e == 0xff - (127 - 15))
Packit 8dc392
    {
Packit 8dc392
	if (m == 0)
Packit 8dc392
	{
Packit 8dc392
	    //
Packit 8dc392
	    // F is an infinity; convert f to a half
Packit 8dc392
	    // infinity with the same sign as f.
Packit 8dc392
	    //
Packit 8dc392
Packit 8dc392
	    return s | 0x7c00;
Packit 8dc392
	}
Packit 8dc392
	else
Packit 8dc392
	{
Packit 8dc392
	    //
Packit 8dc392
	    // F is a NAN; we produce a half NAN that preserves
Packit 8dc392
	    // the sign bit and the 10 leftmost bits of the
Packit 8dc392
	    // significand of f, with one exception: If the 10
Packit 8dc392
	    // leftmost bits are all zero, the NAN would turn 
Packit 8dc392
	    // into an infinity, so we have to set at least one
Packit 8dc392
	    // bit in the significand.
Packit 8dc392
	    //
Packit 8dc392
Packit 8dc392
	    m >>= 13;
Packit 8dc392
	    return s | 0x7c00 | m | (m == 0);
Packit 8dc392
	}
Packit 8dc392
    }
Packit 8dc392
    else
Packit 8dc392
    {
Packit 8dc392
	//
Packit 8dc392
	// E is greater than zero.  F is a normalized float.
Packit 8dc392
	// We try to convert f to a normalized half.
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Round to m to the nearest 10-bit value.  In case of
Packit 8dc392
	// a tie, round to the nearest even value.
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	m = m + 0x00000fff + ((m >> 13) & 1);
Packit 8dc392
Packit 8dc392
	if (m & 0x00800000)
Packit 8dc392
	{
Packit 8dc392
	    m =  0;		// overflow in significand,
Packit 8dc392
	    e += 1;		// adjust exponent
Packit 8dc392
	}
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Handle exponent overflow
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	if (e > 30)
Packit 8dc392
	{
Packit 8dc392
	    overflow ();	// Cause a hardware floating point overflow;
Packit 8dc392
	    return s | 0x7c00;	// if this returns, the half becomes an
Packit 8dc392
	}   			// infinity with the same sign as f.
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Assemble the half from s, e and m.
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	return s | (e << 10) | (m >> 13);
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
//---------------------
Packit 8dc392
// Stream I/O operators
Packit 8dc392
//---------------------
Packit 8dc392
Packit 8dc392
HALF_EXPORT ostream &
Packit 8dc392
operator << (ostream &os, half h)
Packit 8dc392
{
Packit 8dc392
    os << float (h);
Packit 8dc392
    return os;
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
HALF_EXPORT istream &
Packit 8dc392
operator >> (istream &is, half &h)
Packit 8dc392
{
Packit 8dc392
    float f;
Packit 8dc392
    is >> f;
Packit 8dc392
    h = half (f);
Packit 8dc392
    return is;
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
//---------------------------------------
Packit 8dc392
// Functions to print the bit-layout of
Packit 8dc392
// floats and halfs, mostly for debugging
Packit 8dc392
//---------------------------------------
Packit 8dc392
Packit 8dc392
HALF_EXPORT void
Packit 8dc392
printBits (ostream &os, half h)
Packit 8dc392
{
Packit 8dc392
    unsigned short b = h.bits();
Packit 8dc392
Packit 8dc392
    for (int i = 15; i >= 0; i--)
Packit 8dc392
    {
Packit 8dc392
	os << (((b >> i) & 1)? '1': '0');
Packit 8dc392
Packit 8dc392
	if (i == 15 || i == 10)
Packit 8dc392
	    os << ' ';
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
HALF_EXPORT void
Packit 8dc392
printBits (ostream &os, float f)
Packit 8dc392
{
Packit 8dc392
    half::uif x;
Packit 8dc392
    x.f = f;
Packit 8dc392
Packit 8dc392
    for (int i = 31; i >= 0; i--)
Packit 8dc392
    {
Packit 8dc392
	os << (((x.i >> i) & 1)? '1': '0');
Packit 8dc392
Packit 8dc392
	if (i == 31 || i == 23)
Packit 8dc392
	    os << ' ';
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
HALF_EXPORT void
Packit 8dc392
printBits (char c[19], half h)
Packit 8dc392
{
Packit 8dc392
    unsigned short b = h.bits();
Packit 8dc392
Packit 8dc392
    for (int i = 15, j = 0; i >= 0; i--, j++)
Packit 8dc392
    {
Packit 8dc392
	c[j] = (((b >> i) & 1)? '1': '0');
Packit 8dc392
Packit 8dc392
	if (i == 15 || i == 10)
Packit 8dc392
	    c[++j] = ' ';
Packit 8dc392
    }
Packit 8dc392
    
Packit 8dc392
    c[18] = 0;
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
HALF_EXPORT void
Packit 8dc392
printBits (char c[35], float f)
Packit 8dc392
{
Packit 8dc392
    half::uif x;
Packit 8dc392
    x.f = f;
Packit 8dc392
Packit 8dc392
    for (int i = 31, j = 0; i >= 0; i--, j++)
Packit 8dc392
    {
Packit 8dc392
	c[j] = (((x.i >> i) & 1)? '1': '0');
Packit 8dc392
Packit 8dc392
	if (i == 31 || i == 23)
Packit 8dc392
	    c[++j] = ' ';
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    c[34] = 0;
Packit 8dc392
}