diff -r 32762c55c099 -r 1ea80d1ded0c HalfFloatArray.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HalfFloatArray.st Tue Feb 04 18:05:02 2014 +0100 @@ -0,0 +1,246 @@ +" + COPYRIGHT (c) 2014 by Claus Gittinger + All Rights Reserved + + This software is furnished under a license and may be used + only in accordance with the terms of that license and with the + inclusion of the above copyright notice. This software may not + be provided or otherwise made available to, or used by, any + other person. No title to or ownership of the software is + hereby transferred. +" +"{ Package: 'stx:libbasic2' }" + +AbstractNumberVector variableWordSubclass:#HalfFloatArray + instanceVariableNames:'' + classVariableNames:'' + poolDictionaries:'' + category:'Collections-Arrayed' +! + +!HalfFloatArray primitiveFunctions! + +%{ +typedef unsigned short halffloat; +typedef unsigned short uint16; +typedef unsigned int uint32; + +// +// convert a halffloat (16-bit float) to a float +// +float +__STX_halffloat_to_float(halffloat h) { + int e; + uint16 hs, he, hm; + uint32 xs, xe, xm; + int32 xes; + union { + uint32 u32; + float f32; + } u; + + if( (h & 0x7FFFu) == 0 ) { // Signed zero + u.u32 = ((uint32) h) << 16; // Return the signed zero + } else { // Not zero + hs = h & 0x8000u; // Pick off sign bit + he = h & 0x7C00u; // Pick off exponent bits + hm = h & 0x03FFu; // Pick off mantissa bits + if( he == 0 ) { // Denormal will convert to normalized + e = -1; // The following loop figures out how much extra to adjust the exponent + do { + e++; + hm <<= 1; + } while( (hm & 0x0400u) == 0 ); // Shift until leading bit overflows into exponent bit + xs = ((uint32) hs) << 16; // Sign bit + xes = ((uint32) (he >> 10)) - 15 + 127 - e; // Exponent unbias the halfp, then bias the single + xe = (uint32) (xes << 23); // Exponent + xm = ((uint32) (hm & 0x03FFu)) << 13; // Mantissa + u.u32 = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits + } else if( he == 0x7C00u ) { // Inf or NaN (all the exponent bits are set) + if( hm == 0 ) { // If mantissa is zero ... + u.u32 = (((uint32) hs) << 16) | ((uint32) 0x7F800000u); // Signed Inf + } else { + u.u32 = (uint32) 0xFFC00000u; // NaN, only 1st mantissa bit set + } + } else { // Normalized number + xs = ((uint32) hs) << 16; // Sign bit + xes = ((uint32) (he >> 10)) - 15 + 127; // Exponent unbias the halfp, then bias the single + xe = (uint32) (xes << 23); // Exponent + xm = ((uint32) hm) << 13; // Mantissa + u.u32 = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits + } + } + return u.f32; +} + +// +// convert a float to a halffloat (16-bit float) +// +halffloat +__STX_float_to_halffloat(float f32) { + uint16 hs, he, hm; + uint32 x, xs, xe, xm; + int hes; + union { + uint32 u32; + float f32; + } u; + halffloat h; + + u.f32 = f32; + x = u.u32; + if( (x & 0x7FFFFFFFu) == 0 ) { // Signed zero + h = (uint16) (x >> 16); // Return the signed zero + } else { // Not zero + xs = x & 0x80000000u; // Pick off sign bit + xe = x & 0x7F800000u; // Pick off exponent bits + xm = x & 0x007FFFFFu; // Pick off mantissa bits + if( xe == 0 ) { // Denormal will underflow, return a signed zero + h = (uint16) (xs >> 16); + } else if( xe == 0x7F800000u ) { // Inf or NaN (all the exponent bits are set) + if( xm == 0 ) { // If mantissa is zero ... + h = (uint16) ((xs >> 16) | 0x7C00u); // Signed Inf + } else { + h = (uint16) 0xFE00u; // NaN, only 1st mantissa bit set + } + } else { // Normalized number + hs = (uint16) (xs >> 16); // Sign bit + hes = ((int)(xe >> 23)) - 127 + 15; // Exponent unbias the single, then bias the halfp + if( hes >= 0x1F ) { // Overflow + h = (uint16) ((xs >> 16) | 0x7C00u); // Signed Inf + } else if( hes <= 0 ) { // Underflow + if( (14 - hes) > 24 ) { // Mantissa shifted all the way off & no rounding possibility + hm = (uint16) 0u; // Set mantissa to zero + } else { + xm |= 0x00800000u; // Add the hidden leading bit + hm = (uint16) (xm >> (14 - hes)); // Mantissa + if( (xm >> (13 - hes)) & 0x00000001u ) // Check for rounding + hm += (uint16) 1u; // Round, might overflow into exp bit, but this is OK + } + h = (hs | hm); // Combine sign bit and mantissa bits, biased exponent is zero + } else { + he = (uint16) (hes << 10); // Exponent + hm = (uint16) (xm >> 13); // Mantissa + if( xm & 0x00001000u ) // Check for rounding + h = (hs | he | hm) + (uint16) 1u; // Round, might overflow to inf, this is OK + else + h = (hs | he | hm); // No rounding + } + } + } + return h; +} + +%} +! + +!HalfFloatArray class methodsFor:'documentation'! + +copyright +" + COPYRIGHT (c) 1993 by Claus Gittinger + All Rights Reserved + + This software is furnished under a license and may be used + only in accordance with the terms of that license and with the + inclusion of the above copyright notice. This software may not + be provided or otherwise made available to, or used by, any + other person. No title to or ownership of the software is + hereby transferred. +" +! + +documentation +" + HalfFloatArrays store half precision (16bit) floats (and nothing else). + HalfFloats were trditionally seldom used, but seem to become more popular + these days, as some 3D graphics accelerators and game engines use them + for very dens and compact storage. + Notice, that when accessing a HalfFloats elements via getters/setters, + shortFloat (i.e. single precision 32bit floats are exchanged). + HalfFloats are not supported as first class objects by the st/x system (yet?). + + [memory requirements:] + OBJ-HEADER + (size * 2) + + [See also:] + FloatArray DoubleArray Array + + [author:] + Claus Gittinger +" +! ! + +!HalfFloatArray class methodsFor:'queries'! + +elementByteSize + ^ 2 +! ! + + +!HalfFloatArray methodsFor:'accessing'! + +at:index +%{ /* NOCONTEXT */ + if (__isSmallInteger(index)) { + int i = __intVal(index); + + if ((unsigned int)i <= __wordArraySize(self)) { + unsigned short h; + OBJ newFloat; + float f; + + h = __WordArrayInstPtr(self)->s_element[i]; + + f = __STX_halffloat_to_float(h); + __qMKSFLOAT(newFloat, f); + RETURN ( newFloat ); + } + } +%}. + self primitiveFailed +! + +at:index put:aFloat +%{ + if (__isSmallInteger(index)) { + int i = __intVal(index); + + if ((unsigned)i <= __wordArraySize(self)) { + unsigned short h; + float f; + + if (__isFloat(aFloat)) { + f = (float)(__floatVal(aFloat)); + } else if (__isShortFloat(aFloat)) { + f = __shortFloatVal(aFloat); + } else if (__isSmallInteger(aFloat)) { + f = (float)(__intVal(aFloat)); + } else + goto error; + + h = __STX_float_to_halffloat(f); + __WordArrayInstPtr(self)->s_element[i] = h; + RETURN (aFloat); + } + } + error: ; +%}. + self primitiveFailed +! ! + +!HalfFloatArray methodsFor:'queries'! + +defaultElement + ^ ShortFloat zero +! + +numFloats + ^ self size +! ! + +!HalfFloatArray class methodsFor:'documentation'! + +version_CVS + ^ '$Header: /cvs/stx/stx/libbasic2/HalfFloatArray.st,v 1.1 2014-02-04 17:05:02 cg Exp $' +! !