00001 #region --- License ---
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #endregion --- License ---
00058
00059 using System;
00060 using System.IO;
00061 using System.Runtime.InteropServices;
00062 using System.Runtime.Serialization;
00063
00064 namespace OpenTK
00065 {
00066
00078 [Serializable, StructLayout(LayoutKind.Sequential)]
00079 public struct Half : ISerializable, IComparable<Half>, IFormattable, IEquatable<Half>
00080 {
00081 #region Internal Field
00082
00083 UInt16 bits;
00084
00085 #endregion Internal Field
00086
00087 #region Properties
00088
00090 public bool IsZero { get { return (bits == 0) || (bits == 0x8000); } }
00091
00093 public bool IsNaN { get { return (((bits & 0x7C00) == 0x7C00) && (bits & 0x03FF) != 0x0000); } }
00094
00096 public bool IsPositiveInfinity { get { return (bits == 31744); } }
00097
00099 public bool IsNegativeInfinity { get { return (bits == 64512); } }
00100
00101 #endregion Properties
00102
00103 #region Constructors
00104
00109 public Half(Single f)
00110 : this()
00111 {
00112 unsafe
00113 {
00114 bits = SingleToHalf(*(int*)&f);
00115 }
00116 }
00117
00123 public Half(Single f, bool throwOnError)
00124 : this(f)
00125 {
00126 if (throwOnError)
00127 {
00128
00129 if (f > Half.MaxValue) throw new ArithmeticException("Half: Positive maximum value exceeded.");
00130 if (f < -Half.MaxValue) throw new ArithmeticException("Half: Negative minimum value exceeded.");
00131
00132
00133 if (Single.IsNaN(f)) throw new ArithmeticException("Half: Input is not a number (NaN).");
00134 if (Single.IsPositiveInfinity(f)) throw new ArithmeticException("Half: Input is positive infinity.");
00135 if (Single.IsNegativeInfinity(f)) throw new ArithmeticException("Half: Input is negative infinity.");
00136 }
00137 }
00138
00143 public Half(Double d) : this((Single)d) { }
00144
00150 public Half(Double d, bool throwOnError) : this((Single)d, throwOnError) { }
00151
00152 #endregion Constructors
00153
00154 #region Single -> Half
00155
00157 private UInt16 SingleToHalf(Int32 si32)
00158 {
00159
00160
00161
00162
00163
00164 Int32 sign = (si32 >> 16) & 0x00008000;
00165 Int32 exponent = ((si32 >> 23) & 0x000000ff) - (127 - 15);
00166 Int32 mantissa = si32 & 0x007fffff;
00167
00168
00169
00170 if (exponent <= 0)
00171 {
00172 if (exponent < -10)
00173 {
00174
00175
00176
00177
00178
00179 return (UInt16)sign;
00180 }
00181
00182
00183
00184
00185
00186
00187
00188 mantissa = mantissa | 0x00800000;
00189
00190
00191
00192
00193
00194
00195 Int32 t = 14 - exponent;
00196 Int32 a = (1 << (t - 1)) - 1;
00197 Int32 b = (mantissa >> t) & 1;
00198
00199 mantissa = (mantissa + a + b) >> t;
00200
00201
00202
00203 return (UInt16)(sign | mantissa);
00204 }
00205 else if (exponent == 0xff - (127 - 15))
00206 {
00207 if (mantissa == 0)
00208 {
00209
00210
00211 return (UInt16)(sign | 0x7c00);
00212 }
00213 else
00214 {
00215
00216
00217
00218
00219 mantissa >>= 13;
00220 return (UInt16)(sign | 0x7c00 | mantissa | ((mantissa == 0) ? 1 : 0));
00221 }
00222 }
00223 else
00224 {
00225
00226
00227
00228
00229 mantissa = mantissa + 0x00000fff + ((mantissa >> 13) & 1);
00230
00231 if ((mantissa & 0x00800000) == 1)
00232 {
00233 mantissa = 0;
00234 exponent += 1;
00235 }
00236
00237
00238 if (exponent > 30) throw new ArithmeticException("Half: Hardware floating-point overflow.");
00239
00240
00241
00242 return (UInt16)(sign | (exponent << 10) | (mantissa >> 13));
00243 }
00244 }
00245
00246 #endregion Single -> Half
00247
00248 #region Half -> Single
00249
00252 public Single ToSingle()
00253 {
00254 int i = HalfToFloat(bits);
00255
00256 unsafe
00257 {
00258 return *(float*)&i;
00259 }
00260 }
00261
00263 private Int32 HalfToFloat(UInt16 ui16)
00264 {
00265
00266 Int32 sign = (ui16 >> 15) & 0x00000001;
00267 Int32 exponent = (ui16 >> 10) & 0x0000001f;
00268 Int32 mantissa = ui16 & 0x000003ff;
00269
00270 if (exponent == 0)
00271 {
00272 if (mantissa == 0)
00273 {
00274
00275
00276 return sign << 31;
00277 }
00278 else
00279 {
00280
00281
00282 while ((mantissa & 0x00000400) == 0)
00283 {
00284 mantissa <<= 1;
00285 exponent -= 1;
00286 }
00287
00288 exponent += 1;
00289 mantissa &= ~0x00000400;
00290 }
00291 }
00292 else if (exponent == 31)
00293 {
00294 if (mantissa == 0)
00295 {
00296
00297
00298 return (sign << 31) | 0x7f800000;
00299 }
00300 else
00301 {
00302
00303
00304 return (sign << 31) | 0x7f800000 | (mantissa << 13);
00305 }
00306 }
00307
00308
00309
00310 exponent = exponent + (127 - 15);
00311 mantissa = mantissa << 13;
00312
00313
00314
00315 return (sign << 31) | (exponent << 23) | mantissa;
00316 }
00317
00318 #endregion Half -> Single
00319
00320 #region Conversions
00321
00331 public static explicit operator Half(float f)
00332 {
00333 return new Half(f);
00334 }
00335
00345 public static explicit operator Half(double d)
00346 {
00347 return new Half(d);
00348 }
00349
00359 public static implicit operator float(Half h)
00360 {
00361 return h.ToSingle();
00362 }
00363
00373 public static implicit operator double(Half h)
00374 {
00375 return (double)h.ToSingle();
00376 }
00377
00378 #endregion Conversions
00379
00380 #region Constants
00381
00383 public static readonly Int32 SizeInBytes = 2;
00384
00386 public static readonly Single MinValue = 5.96046448e-08f;
00387
00389 public static readonly Single MinNormalizedValue = 6.10351562e-05f;
00390
00392 public static readonly Single MaxValue = 65504.0f;
00393
00395 public static readonly Single Epsilon = 0.00097656f;
00396
00397 #endregion Constants
00398
00399 #region ISerializable
00400
00404 public Half(SerializationInfo info, StreamingContext context)
00405 {
00406 this.bits = (ushort)info.GetValue("bits", typeof(ushort));
00407 }
00408
00412 public void GetObjectData(SerializationInfo info, StreamingContext context)
00413 {
00414 info.AddValue("bits", this.bits);
00415 }
00416
00417 #endregion ISerializable
00418
00419 #region Binary dump
00420
00423 public void FromBinaryStream(BinaryReader bin)
00424 {
00425 this.bits = bin.ReadUInt16();
00426
00427 }
00428
00431 public void ToBinaryStream(BinaryWriter bin)
00432 {
00433 bin.Write(this.bits);
00434 }
00435
00436 #endregion Binary dump
00437
00438 #region IEquatable<Half> Members
00439
00440 const int maxUlps = 1;
00441
00447 public bool Equals(Half other)
00448 {
00449 short aInt, bInt;
00450 unchecked { aInt = (short)other.bits; }
00451 unchecked { bInt = (short)this.bits; }
00452
00453
00454 if (aInt < 0)
00455 aInt = (short)(0x8000 - aInt);
00456
00457
00458 if (bInt < 0)
00459 bInt = (short)(0x8000 - bInt);
00460
00461 short intDiff = System.Math.Abs((short)(aInt - bInt));
00462
00463 if (intDiff <= maxUlps)
00464 return true;
00465
00466 return false;
00467 }
00468
00469 #endregion
00470
00471 #region IComparable<Half> Members
00472
00490 public int CompareTo(Half other)
00491 {
00492 return ((float)this).CompareTo((float)other);
00493 }
00494
00495 #endregion IComparable<Half> Members
00496
00497 #region IFormattable Members
00498
00501 public override string ToString()
00502 {
00503 return this.ToSingle().ToString();
00504 }
00505
00510 public string ToString(string format, IFormatProvider formatProvider)
00511 {
00512 return this.ToSingle().ToString(format, formatProvider);
00513 }
00514
00515 #endregion IFormattable Members
00516
00517 #region String -> Half
00518
00522 public static Half Parse(string s)
00523 {
00524 return (Half)Single.Parse(s);
00525 }
00526
00532 public static Half Parse(string s, System.Globalization.NumberStyles style, IFormatProvider provider)
00533 {
00534 return (Half)Single.Parse(s, style, provider);
00535 }
00536
00541 public static bool TryParse(string s, out Half result)
00542 {
00543 float f;
00544 bool b = Single.TryParse(s, out f);
00545 result = (Half)f;
00546 return b;
00547 }
00548
00555 public static bool TryParse(string s, System.Globalization.NumberStyles style, IFormatProvider provider, out Half result)
00556 {
00557 float f;
00558 bool b = Single.TryParse(s, style, provider, out f);
00559 result = (Half)f;
00560 return b;
00561 }
00562
00563 #endregion String -> Half
00564
00565 #region BitConverter
00566
00570 public static byte[] GetBytes(Half h)
00571 {
00572 return BitConverter.GetBytes(h.bits);
00573 }
00574
00579 public static Half FromBytes(byte[] value, int startIndex)
00580 {
00581 Half h;
00582 h.bits = BitConverter.ToUInt16(value, startIndex);
00583 return h;
00584 }
00585
00586 #endregion BitConverter
00587 }
00588 }