├── .gitignore ├── Readme.txt ├── SoftFloat.sln └── SoftFloatTest ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── SoftFloat.cs ├── SoftFloatTest.csproj └── Tests.cs /.gitignore: -------------------------------------------------------------------------------- 1 | *.suo 2 | *.user 3 | *.ncb 4 | *.psess 5 | *.vsp 6 | .svn/ 7 | bin/ 8 | obj/ 9 | Debug/ 10 | Release/ -------------------------------------------------------------------------------- /Readme.txt: -------------------------------------------------------------------------------- 1 | # SoftFloat floating point library 2 | Certain network architectures require deterministic math. Since the normal `Single`/`Double` classes in .net can beave differently on different hardware they can't be used. Thus I decided to write a software implementation of 32 bit floating points. 3 | 4 | The `SoftFloat` struct contains a 32 bit integer whose value conforms to the `binary32` datatype from IEEE 754. This means reinterpret casts to `Single`/`float` are possible. SubNorms, infinities and `NaN`s are supported. 5 | 6 | The results for the basic operations should be within one step of the correct result(i.e. there may be small rounding errors). The complex operations may have larger errors. 7 | 8 | Performance is an important goal. So if you see a way to make it faster, please contact me. 9 | 10 | While I'm using a permissive license, I'd still be happy if you contributed back any improvements you make. -------------------------------------------------------------------------------- /SoftFloat.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoftFloatTest", "SoftFloatTest\SoftFloatTest.csproj", "{A548EBEE-5FC1-41CF-BFFE-B6F908F15753}" 5 | EndProject 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EDA94536-C376-49B0-AF37-020C8E9B7842}" 7 | ProjectSection(SolutionItems) = preProject 8 | Performance1.psess = Performance1.psess 9 | Performance2.psess = Performance2.psess 10 | EndProjectSection 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x86 = Debug|x86 16 | Release|Any CPU = Release|Any CPU 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {A548EBEE-5FC1-41CF-BFFE-B6F908F15753}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {A548EBEE-5FC1-41CF-BFFE-B6F908F15753}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {A548EBEE-5FC1-41CF-BFFE-B6F908F15753}.Debug|x86.ActiveCfg = Debug|x86 23 | {A548EBEE-5FC1-41CF-BFFE-B6F908F15753}.Debug|x86.Build.0 = Debug|x86 24 | {A548EBEE-5FC1-41CF-BFFE-B6F908F15753}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {A548EBEE-5FC1-41CF-BFFE-B6F908F15753}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {A548EBEE-5FC1-41CF-BFFE-B6F908F15753}.Release|x86.ActiveCfg = Release|x86 27 | {A548EBEE-5FC1-41CF-BFFE-B6F908F15753}.Release|x86.Build.0 = Release|x86 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /SoftFloatTest/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Diagnostics; 6 | 7 | namespace SoftFloatTest 8 | { 9 | class Program 10 | { 11 | static Random random = new Random(); 12 | 13 | static uint RandomUInt32() 14 | { 15 | return (uint)random.Next(int.MinValue, int.MaxValue); 16 | } 17 | 18 | static void Main(string[] args) 19 | { 20 | new Tests(); 21 | 22 | SoftFloat sum = SoftFloat.Zero; 23 | SoftFloat pro = (SoftFloat)1E30f; 24 | float sumFloat = 0; 25 | const int n = 1000000000; 26 | 27 | SoftFloat two = SoftFloat.One + SoftFloat.One; 28 | SoftFloat factor = (SoftFloat)1f; 29 | var x = SoftFloat.Epsilon + SoftFloat.Epsilon; 30 | 31 | Stopwatch watch = new Stopwatch(); 32 | watch.Start(); 33 | for (int i = 0; i < n; i++) 34 | { 35 | //pro *= factor; 36 | //sum += factor; 37 | sumFloat *= 1f; 38 | } 39 | watch.Stop(); 40 | Console.WriteLine(watch.Elapsed + " " + Math.Round(n / watch.Elapsed.TotalSeconds / 1000000, 2) + "M FLOPS"); 41 | Console.WriteLine("" + pro + " " + sumFloat + " " + sum); 42 | 43 | /*for (int i = 0; i < n; i++) 44 | { 45 | uint i1 = RandomUInt32(); 46 | uint i2 = RandomUInt32(); 47 | 48 | SoftFloat sf1 = SoftFloat.FromIeeeRaw(i1); 49 | SoftFloat sf2 = SoftFloat.FromIeeeRaw(i2); 50 | SoftFloat sf = sf1 * sf2; 51 | 52 | float f1 = (float)sf1; 53 | float f2 = (float)sf2; 54 | float f = f1 * f2; 55 | SoftFloat sfc = (SoftFloat)f; 56 | 57 | long error = SoftFloat.RawDistance(sf, sfc); 58 | if (error > 1) 59 | { 60 | Console.WriteLine(sf1.ToIeeeRaw() + " + " + sf2.ToIeeeRaw() + 61 | " is " + sf.ToIeeeRaw() + 62 | " expecting " + sfc.ToIeeeRaw() + 63 | " error=" + error); 64 | } 65 | }*/ 66 | Console.ReadLine(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /SoftFloatTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SoftFloatTest")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("SoftFloatTest")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("6c3362db-ec53-4861-abeb-3599463dd44f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SoftFloatTest/SoftFloat.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 CodesInChaos 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 4 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 6 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 7 | // subject to the following conditions: 8 | 9 | // The above copyright notice and this permission notice shall be included in all copies 10 | // or substantial portions of the Software. 11 | 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 15 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 16 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | // The MIT License (MIT) - http://www.opensource.org/licenses/mit-license.php 20 | // If you need a different license please contact me 21 | 22 | using System; 23 | using System.Collections.Generic; 24 | using System.Linq; 25 | using System.Text; 26 | using System.Diagnostics; 27 | 28 | namespace SoftFloatTest 29 | { 30 | // Internal representation is identical to IEEE binary32 floatingpoints 31 | [DebuggerDisplay("{ToStringInv()}")] 32 | public struct SoftFloat : IEquatable, IComparable, IComparable, IFormattable 33 | { 34 | private readonly uint _raw; 35 | 36 | internal SoftFloat(uint raw) 37 | { 38 | _raw = raw; 39 | } 40 | 41 | private uint RawMantissa { get { return _raw & 0x7FFFFF; } } 42 | private int Mantissa 43 | { 44 | get 45 | { 46 | if (RawExponent != 0) 47 | { 48 | uint sign = (uint)((int)_raw >> 31); 49 | return (int)(((RawMantissa | 0x800000) ^ sign) - sign); 50 | } 51 | else 52 | { 53 | uint sign = (uint)((int)_raw >> 31); 54 | return (int)(((RawMantissa) ^ sign) - sign); 55 | } 56 | } 57 | } 58 | 59 | private sbyte Exponent { get { return (sbyte)(RawExponent - ExponentBias); } } 60 | 61 | private byte RawExponent { get { return (byte)(_raw >> MantissaBits); } } 62 | 63 | 64 | private const uint SignMask = 0x80000000; 65 | private const int MantissaBits = 23; 66 | private const int ExponentBias = 127; 67 | 68 | private const uint RawZero = 0; 69 | private const uint RawNaN = 0xFFC00000;//same as float.NaN 70 | private const uint RawPositiveInfinity = 0x7F800000; 71 | private const uint RawNegativeInfinity = RawPositiveInfinity ^ SignMask; 72 | private const uint RawOne = 0x3F800000; 73 | private const uint RawMinusOne = RawOne ^ SignMask; 74 | private const uint RawMaxValue = 0x7F7FFFFF; 75 | private const uint RawMinValue = 0x7F7FFFFF ^ SignMask; 76 | private const uint RawEpsilon = 0x00000001; 77 | private const uint RawOneOverLog2Of10 = 0;//Fixme 78 | private const uint RawOneOverLog2OfE = 0;//Fixme 79 | private const uint RawLog2OfE = 0; 80 | 81 | 82 | public static SoftFloat Zero { get { return new SoftFloat(); } } 83 | public static SoftFloat PositiveInfinity { get { return new SoftFloat(RawPositiveInfinity); } } 84 | public static SoftFloat NegativeInfinity { get { return new SoftFloat(RawNegativeInfinity); } } 85 | public static SoftFloat NaN { get { return new SoftFloat(RawNaN); } } 86 | public static SoftFloat One { get { return new SoftFloat(RawOne); } } 87 | public static SoftFloat MinusOne { get { return new SoftFloat(RawMinusOne); } } 88 | public static SoftFloat MaxValue { get { return new SoftFloat(RawMaxValue); } } 89 | public static SoftFloat MinValue { get { return new SoftFloat(RawMinValue); } } 90 | public static SoftFloat Epsilon { get { return new SoftFloat(RawEpsilon); } } 91 | 92 | public override string ToString() 93 | { 94 | return ((float)this).ToString(); 95 | } 96 | 97 | public static explicit operator SoftFloat(float f) 98 | { 99 | uint raw = ReinterpretFloatToInt32(f); 100 | return new SoftFloat(raw); 101 | } 102 | 103 | public static explicit operator float(SoftFloat f) 104 | { 105 | uint raw = f._raw; 106 | return ReinterpretIntToFloat32(raw); 107 | } 108 | 109 | public static SoftFloat operator -(SoftFloat f) 110 | { 111 | return new SoftFloat(f._raw ^ 0x80000000); 112 | } 113 | 114 | 115 | 116 | public static SoftFloat operator +(SoftFloat f1, SoftFloat f2) 117 | { 118 | byte rawExp1 = f1.RawExponent; 119 | byte rawExp2 = f2.RawExponent; 120 | int deltaExp = rawExp1 - rawExp2; 121 | if (deltaExp >= 0) 122 | { 123 | if (rawExp1 != 255) 124 | {//Finite 125 | if (deltaExp > 25) 126 | return f1; 127 | int man1; 128 | int man2; 129 | if (rawExp2 != 0) 130 | { 131 | //man1 = f1.Mantissa 132 | //http://graphics.stanford.edu/~seander/bithacks.html#ConditionalNegate 133 | uint sign1 = (uint)((int)f1._raw >> 31); 134 | man1 = (int)(((f1.RawMantissa | 0x800000) ^ sign1) - sign1); 135 | //man2 = f2.Mantissa 136 | uint sign2 = (uint)((int)f2._raw >> 31); 137 | man2 = (int)(((f2.RawMantissa | 0x800000) ^ sign2) - sign2); 138 | } 139 | else 140 | {//Subnorm 141 | //man2 = f2.Mantissa 142 | uint sign2 = (uint)((int)f2._raw >> 31); 143 | man2 = (int)((f2.RawMantissa ^ sign2) - sign2); 144 | 145 | man1 = f1.Mantissa; 146 | 147 | rawExp2 = 1; 148 | if (rawExp1 == 0) 149 | rawExp1 = 1; 150 | deltaExp = rawExp1 - rawExp2; 151 | } 152 | int man = (man1 << 6) + ((man2 << 6) >> deltaExp); 153 | uint absMan = (uint)Math.Abs(man); 154 | if (absMan == 0) 155 | return Zero; 156 | uint msb = absMan >> 23; 157 | int rawExp = rawExp1 - 6; 158 | while (msb == 0) 159 | { 160 | rawExp -= 8; 161 | absMan <<= 8; 162 | msb = absMan >> 23; 163 | } 164 | int msbIndex = BitScanReverse8(msb); 165 | rawExp += msbIndex; 166 | absMan >>= msbIndex; 167 | if ((uint)(rawExp - 1) < 254) 168 | { 169 | uint raw = (uint)man & 0x80000000 | (uint)rawExp << 23 | (absMan & 0x7FFFFF); 170 | return new SoftFloat(raw); 171 | } 172 | else 173 | { 174 | if (rawExp >= 255) 175 | {//Overflow 176 | if (man >= 0) 177 | return PositiveInfinity; 178 | else 179 | return NegativeInfinity; 180 | } 181 | if (rawExp >= -24)//Fixme 182 | { 183 | uint raw = (uint)man & 0x80000000 | absMan >> (-rawExp + 1); 184 | return new SoftFloat(raw); 185 | } 186 | return Zero; 187 | } 188 | } 189 | else 190 | {//special 191 | 192 | if (rawExp2 != 255)//f1 is NaN, +Inf, -Inf and f2 is finite 193 | return f1; 194 | // Both not finite 195 | if (f1._raw == f2._raw) 196 | return f1; 197 | else 198 | return NaN; 199 | } 200 | 201 | } 202 | else 203 | { 204 | //ToDo manually write this code 205 | return f2 + f1;//flip operands 206 | } 207 | } 208 | 209 | public static SoftFloat operator -(SoftFloat f1, SoftFloat f2) 210 | { 211 | return f1 + (-f2); 212 | } 213 | 214 | public static SoftFloat operator *(SoftFloat f1, SoftFloat f2) 215 | { 216 | int man1; 217 | int rawExp1 = f1.RawExponent; 218 | uint sign1; 219 | uint sign2; 220 | if (rawExp1 == 0) 221 | {//SubNorm 222 | //man1 = f1.Mantissa 223 | sign1 = (uint)((int)f1._raw >> 31); 224 | uint rawMan1 = f1.RawMantissa; 225 | if (rawMan1 == 0 && f2.IsFinite()) 226 | return new SoftFloat((f1._raw ^ f2._raw) & SignMask); 227 | rawExp1 = 1; 228 | while ((rawMan1 & 0x800000) == 0) 229 | { 230 | rawMan1 <<= 1; 231 | rawExp1--; 232 | } 233 | Debug.Assert(rawMan1 >> 23 == 1); 234 | man1 = (int)((rawMan1 ^ sign1) - sign1); 235 | } 236 | else if (rawExp1 != 255) 237 | {//Norm 238 | //man1 = f1.Mantissa 239 | sign1 = (uint)((int)f1._raw >> 31); 240 | man1 = (int)(((f1.RawMantissa | 0x800000) ^ sign1) - sign1); 241 | } 242 | else 243 | {//Non finite 244 | if (f1._raw == RawPositiveInfinity) 245 | { 246 | if (f2.IsZero()) 247 | return SoftFloat.NaN; 248 | if (f2.IsNaN()) 249 | return f2; 250 | if ((int)f2._raw >= 0) 251 | return PositiveInfinity; 252 | else 253 | return NegativeInfinity; 254 | } 255 | else if (f1._raw == RawNegativeInfinity) 256 | { 257 | if (f2.IsZero()) 258 | return SoftFloat.NaN; 259 | if (f2.IsNaN()) 260 | return f2; 261 | if ((int)f2._raw < 0) 262 | return PositiveInfinity; 263 | else 264 | return NegativeInfinity; 265 | } 266 | else return f1; 267 | } 268 | 269 | int man2; 270 | int rawExp2 = f2.RawExponent; 271 | if (rawExp2 == 0) 272 | {//SubNorm 273 | //man2 = f2.Mantissa 274 | sign2 = (uint)((int)f2._raw >> 31); 275 | uint rawMan2 = f2.RawMantissa; 276 | if (rawMan2 == 0) 277 | return new SoftFloat((f1._raw ^ f2._raw) & SignMask); 278 | rawExp2 = 1; 279 | while ((rawMan2 & 0x800000) == 0) 280 | { 281 | rawMan2 <<= 1; 282 | rawExp2--; 283 | } 284 | Debug.Assert(rawMan2 >> 23 == 1); 285 | man2 = (int)((rawMan2 ^ sign2) - sign2); 286 | } 287 | else if (rawExp2 != 255) 288 | {//Norm 289 | //man2 = f2.Mantissa 290 | sign2 = (uint)((int)f2._raw >> 31); 291 | man2 = (int)(((f2.RawMantissa | 0x800000) ^ sign2) - sign2); 292 | } 293 | else 294 | {//Non finite 295 | if (f2._raw == RawPositiveInfinity) 296 | { 297 | if (f1.IsZero()) 298 | return SoftFloat.NaN; 299 | if ((int)f1._raw >= 0) 300 | return PositiveInfinity; 301 | else 302 | return NegativeInfinity; 303 | } 304 | else if (f2._raw == RawNegativeInfinity) 305 | { 306 | if (f1.IsZero()) 307 | return SoftFloat.NaN; 308 | if ((int)f1._raw < 0) 309 | return PositiveInfinity; 310 | else 311 | return NegativeInfinity; 312 | } 313 | else return f2; 314 | } 315 | 316 | long longMan = (long)man1 * (long)man2; 317 | int man = (int)(longMan >> 23); 318 | Debug.Assert(man != 0); 319 | uint absMan = (uint)Math.Abs(man); 320 | int rawExp = rawExp1 + rawExp2 - ExponentBias; 321 | uint sign = (uint)man & 0x80000000; 322 | if ((absMan & 0x1000000) != 0) 323 | { 324 | absMan >>= 1; 325 | rawExp++; 326 | } 327 | Debug.Assert(absMan >> 23 == 1); 328 | if (rawExp >= 255) 329 | return new SoftFloat(sign ^ RawPositiveInfinity);//Overflow 330 | 331 | if (rawExp <= 0) 332 | {//Subnorms/Underflow 333 | if (rawExp <= -24)//Fixme - check correct value 334 | return new SoftFloat(sign); 335 | absMan >>= -rawExp + 1; 336 | rawExp = 0; 337 | } 338 | 339 | uint raw = sign | (uint)rawExp << 23 | absMan & 0x7FFFFF; 340 | return new SoftFloat(raw); 341 | } 342 | 343 | public static SoftFloat operator /(SoftFloat f1, SoftFloat f2) 344 | { 345 | throw new NotImplementedException(); 346 | } 347 | 348 | private static readonly sbyte[] msb = new sbyte[256]; 349 | private static int BitScanReverse8(uint b) 350 | { 351 | return msb[b]; 352 | } 353 | 354 | private static unsafe uint ReinterpretFloatToInt32(float f) 355 | { 356 | return *((uint*)&f); 357 | } 358 | 359 | private static unsafe float ReinterpretIntToFloat32(uint i) 360 | { 361 | return *((float*)&i); 362 | } 363 | 364 | public override bool Equals(object obj) 365 | { 366 | if (obj == null || GetType() != obj.GetType()) 367 | { 368 | return false; 369 | } 370 | return this.Equals((SoftFloat)obj); 371 | } 372 | 373 | public bool Equals(SoftFloat other) 374 | { 375 | if (this.RawExponent != 255) 376 | { 377 | return (this._raw == other._raw) || 378 | ((this._raw & 0x7FFFFFFF) == 0) && ((other._raw & 0x7FFFFFFF) == 0);//0==-0 379 | } 380 | else 381 | { 382 | if (this.RawMantissa == 0) 383 | return this._raw == other._raw;//infinities 384 | else 385 | return other.RawMantissa != 0;//NaNs are equal for `Equals` (as opposed to the == operator) 386 | } 387 | } 388 | 389 | public override int GetHashCode() 390 | { 391 | if (this._raw == SignMask) 392 | return 0;// +0 equals -0 393 | if (!IsNaN(this)) 394 | return (int)this._raw; 395 | else 396 | return unchecked((int)RawNaN);//All NaNs are equal 397 | } 398 | 399 | public static bool operator ==(SoftFloat f1, SoftFloat f2) 400 | { 401 | if (f1.RawExponent != 255) 402 | { 403 | return (f1._raw == f2._raw) || 404 | ((f1._raw & 0x7FFFFFFF) == 0) && ((f2._raw & 0x7FFFFFFF) == 0);//0==-0 405 | } 406 | else 407 | { 408 | if (f1.RawMantissa == 0) 409 | return f1._raw == f2._raw;//infinities 410 | else 411 | return false;//NaNs 412 | } 413 | } 414 | 415 | public static bool operator !=(SoftFloat f1, SoftFloat f2) 416 | { 417 | return !(f1 == f2); 418 | } 419 | 420 | static SoftFloat() 421 | { 422 | //Init MostSignificantBit table 423 | for (int i = 0; i < 256; i++) 424 | { 425 | sbyte value = 7;//128-255 426 | if (i < 128)//64-127 427 | value = 6; 428 | if (i < 64)//32-63 429 | value = 5; 430 | if (i < 32)//16-31 431 | value = 4; 432 | if (i < 16)//8-15 433 | value = 3; 434 | if (i < 8)//4-7 435 | value = 2; 436 | if (i < 4)//2-3 437 | value = 1; 438 | if (i < 2)//1 439 | value = 0; 440 | if (i < 1)//0 441 | value = -1; 442 | msb[i] = value; 443 | } 444 | } 445 | 446 | public static bool operator <(SoftFloat f1, SoftFloat f2) 447 | { 448 | if (f1.IsNaN() || f2.IsNaN()) 449 | return false; 450 | return f1.CompareTo(f2) < 0; 451 | } 452 | 453 | public static bool operator >(SoftFloat f1, SoftFloat f2) 454 | { 455 | if (f1.IsNaN() || f2.IsNaN()) 456 | return false; 457 | return f1.CompareTo(f2) > 0; 458 | } 459 | 460 | public static bool operator <=(SoftFloat f1, SoftFloat f2) 461 | { 462 | if (f1.IsNaN() || f2.IsNaN()) 463 | return false; 464 | return f1.CompareTo(f2) <= 0; 465 | } 466 | 467 | public static bool operator >=(SoftFloat f1, SoftFloat f2) 468 | { 469 | if (f1.IsNaN() || f2.IsNaN()) 470 | return false; 471 | return f1.CompareTo(f2) >= 0; 472 | } 473 | 474 | public int CompareTo(SoftFloat other) 475 | { 476 | if (this.IsNaN() && other.IsNaN()) 477 | return 0; 478 | 479 | uint sign1 = (uint)((int)this._raw >> 31); 480 | int val1 = (int)(((this._raw) ^ (sign1 & 0x7FFFFFFF)) - sign1); 481 | 482 | uint sign2 = (uint)((int)other._raw >> 31); 483 | int val2 = (int)(((other._raw) ^ (sign2 & 0x7FFFFFFF)) - sign2); 484 | return val1.CompareTo(val2); 485 | } 486 | 487 | public static bool IsInfinity(SoftFloat f) 488 | { 489 | return (f._raw & 0x7FFFFFFF) == 0x7F800000; 490 | } 491 | 492 | public bool IsInfinity() 493 | { 494 | return (_raw & 0x7FFFFFFF) == 0x7F800000; 495 | } 496 | 497 | public static bool IsNegativeInfinity(SoftFloat f) 498 | { 499 | return f._raw == RawNegativeInfinity; 500 | } 501 | 502 | public bool IsNegativeInfinity() 503 | { 504 | return _raw == RawNegativeInfinity; 505 | } 506 | 507 | public static bool IsPositiveInfinity(SoftFloat f) 508 | { 509 | return f._raw == RawPositiveInfinity; 510 | } 511 | 512 | public bool IsPositiveInfinity() 513 | { 514 | return _raw == RawPositiveInfinity; 515 | } 516 | 517 | public bool IsNaN() 518 | { 519 | return (RawExponent == 255) && !IsInfinity(); 520 | } 521 | 522 | public static bool IsNaN(SoftFloat f) 523 | { 524 | return (f.RawExponent == 255) && !IsInfinity(f); 525 | } 526 | 527 | public static bool IsFinite(SoftFloat f) 528 | { 529 | return f.RawExponent != 255; 530 | } 531 | 532 | public bool IsFinite() 533 | { 534 | return RawExponent != 255; 535 | } 536 | 537 | public bool IsZero() 538 | { 539 | return (_raw & 0x7FFFFFFF) == 0; 540 | } 541 | 542 | public int CompareTo(object obj) 543 | { 544 | if (!(obj is SoftFloat)) 545 | throw new ArgumentException("obj"); 546 | return CompareTo((SoftFloat)obj); 547 | } 548 | 549 | public string ToString(string format, IFormatProvider formatProvider) 550 | { 551 | return ((float)this).ToString(format, formatProvider); 552 | } 553 | 554 | public string ToString(string format) 555 | { 556 | return ((float)this).ToString(format); 557 | } 558 | 559 | public string ToString(IFormatProvider provider) 560 | { 561 | return ((float)this).ToString(provider); 562 | } 563 | 564 | public string ToStringInv() 565 | { 566 | return ((float)this).ToString(System.Globalization.CultureInfo.InvariantCulture); 567 | } 568 | 569 | public static SoftFloat Sqrt(SoftFloat f) 570 | { 571 | if (f < SoftFloat.Zero) 572 | return SoftFloat.NaN; 573 | throw new NotImplementedException(); 574 | } 575 | 576 | public static SoftFloat Exp(SoftFloat f) 577 | { 578 | return Pow2(f * new SoftFloat(RawLog2OfE)); 579 | } 580 | 581 | public static SoftFloat Pow2(SoftFloat f) 582 | { 583 | throw new NotImplementedException(); 584 | } 585 | 586 | public static SoftFloat Abs(SoftFloat f) 587 | { 588 | if (f.RawExponent != 255 || IsInfinity(f)) 589 | return new SoftFloat(f._raw ^ SignMask); 590 | else 591 | return f;//Leave NaN untouched 592 | } 593 | 594 | public static SoftFloat Acos(SoftFloat f) 595 | { 596 | throw new NotImplementedException(); 597 | } 598 | 599 | public static SoftFloat Asin(SoftFloat f) 600 | { 601 | throw new NotImplementedException(); 602 | } 603 | 604 | public static SoftFloat Atan(SoftFloat f) 605 | { 606 | throw new NotImplementedException(); 607 | } 608 | 609 | public static SoftFloat Atan2(SoftFloat y, SoftFloat x) 610 | { 611 | throw new NotImplementedException(); 612 | } 613 | 614 | public static SoftFloat Cos(SoftFloat f) 615 | { 616 | throw new NotImplementedException(); 617 | } 618 | 619 | public static SoftFloat Cosh(SoftFloat f) 620 | { 621 | throw new NotImplementedException(); 622 | } 623 | 624 | public static SoftFloat IEEERemainder(SoftFloat x, SoftFloat y) 625 | { 626 | throw new NotImplementedException(); 627 | } 628 | 629 | public static SoftFloat Ln(SoftFloat f) 630 | { 631 | return Log2(f) * new SoftFloat(RawOneOverLog2OfE); 632 | } 633 | 634 | public static SoftFloat Log2(SoftFloat a) 635 | { 636 | throw new NotImplementedException(); 637 | } 638 | 639 | public static SoftFloat Log(SoftFloat a, SoftFloat newBase) 640 | { 641 | return Log2(a) / Log2(newBase); 642 | } 643 | 644 | public static SoftFloat Log10(SoftFloat f) 645 | { 646 | return Log2(f) * new SoftFloat(RawOneOverLog2Of10); 647 | } 648 | 649 | //Returns NaN iff either argument is NaN 650 | public static SoftFloat Max(SoftFloat val1, SoftFloat val2) 651 | { 652 | if (val1 > val2) 653 | return val1; 654 | else if (IsNaN(val1)) 655 | return val1; 656 | else 657 | return val2; 658 | } 659 | 660 | //Returns NaN iff either argument is NaN 661 | public static SoftFloat Min(SoftFloat val1, SoftFloat val2) 662 | { 663 | if (val1 < val2) 664 | return val1; 665 | else if (IsNaN(val1)) 666 | return val1; 667 | else 668 | return val2; 669 | } 670 | 671 | public static SoftFloat Pow(SoftFloat x, SoftFloat y) 672 | { 673 | throw new NotImplementedException(); 674 | } 675 | 676 | public static int Sign(SoftFloat value) 677 | { 678 | if (IsNaN(value)) 679 | throw new ArithmeticException("Sign doesn't support NaN argument"); 680 | if ((value._raw & 0x7FFFFFFF) == 0) 681 | return 0; 682 | else if ((int)value >= 0) 683 | return 1; 684 | else return -1; 685 | } 686 | 687 | public uint ToIeeeRaw() 688 | { 689 | return _raw; 690 | } 691 | 692 | public static long RawDistance(SoftFloat f1, SoftFloat f2) 693 | { 694 | if (!(SoftFloat.IsFinite(f1) && SoftFloat.IsFinite(f2))) 695 | { 696 | if (f1.Equals(f2)) 697 | return 0; 698 | else 699 | return long.MaxValue; 700 | } 701 | else 702 | { 703 | uint sign1 = (uint)((int)f1._raw >> 31); 704 | int val1 = (int)(((f1._raw) ^ (sign1 & 0x7FFFFFFF)) - sign1); 705 | 706 | uint sign2 = (uint)((int)f2._raw >> 31); 707 | int val2 = (int)(((f2._raw) ^ (sign2 & 0x7FFFFFFF)) - sign2); 708 | 709 | return Math.Abs((long)val1 - (long)val2); 710 | } 711 | } 712 | 713 | public static SoftFloat FromIeeeRaw(uint ieeeRaw) 714 | { 715 | return new SoftFloat(ieeeRaw); 716 | } 717 | } 718 | } 719 | -------------------------------------------------------------------------------- /SoftFloatTest/SoftFloatTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {A548EBEE-5FC1-41CF-BFFE-B6F908F15753} 9 | Exe 10 | Properties 11 | SoftFloatTest 12 | SoftFloatTest 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | x86 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | true 27 | 28 | 29 | x86 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | true 37 | 38 | 39 | true 40 | bin\Debug\ 41 | DEBUG;TRACE 42 | true 43 | full 44 | AnyCPU 45 | bin\Debug\SoftFloatTest.exe.CodeAnalysisLog.xml 46 | true 47 | GlobalSuppressions.cs 48 | prompt 49 | MinimumRecommendedRules.ruleset 50 | ;D:\Ap\VisualStudio2010\Team Tools\Static Analysis Tools\\Rule Sets 51 | false 52 | ;D:\Ap\VisualStudio2010\Team Tools\Static Analysis Tools\FxCop\\Rules 53 | true 54 | 55 | 56 | bin\Release\ 57 | TRACE 58 | true 59 | true 60 | pdbonly 61 | AnyCPU 62 | bin\Release\SoftFloatTest.exe.CodeAnalysisLog.xml 63 | true 64 | GlobalSuppressions.cs 65 | prompt 66 | MinimumRecommendedRules.ruleset 67 | ;D:\Ap\VisualStudio2010\Team Tools\Static Analysis Tools\\Rule Sets 68 | true 69 | ;D:\Ap\VisualStudio2010\Team Tools\Static Analysis Tools\FxCop\\Rules 70 | true 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 95 | -------------------------------------------------------------------------------- /SoftFloatTest/Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Diagnostics; 6 | 7 | namespace SoftFloatTest 8 | { 9 | class Tests 10 | { 11 | public void Assert(bool expr) 12 | { 13 | if (!expr) 14 | { 15 | Debugger.Break(); 16 | throw new ApplicationException("Assert failed"); 17 | } 18 | } 19 | 20 | public bool IsIdentical(SoftFloat f1, SoftFloat f2) 21 | { 22 | return f1.ToIeeeRaw() == f2.ToIeeeRaw(); 23 | } 24 | 25 | public bool IsIdentical(SoftFloat f1, uint i) 26 | { 27 | return f1.ToIeeeRaw() == i; 28 | } 29 | 30 | private bool IsIdentical(SoftFloat f1, float f2) 31 | { 32 | return f1.ToIeeeRaw() == ((SoftFloat)f2).ToIeeeRaw(); 33 | } 34 | 35 | public void Representation() 36 | { 37 | Assert(IsIdentical(SoftFloat.Zero, 0f)); 38 | Assert(IsIdentical(-SoftFloat.Zero, -0f)); 39 | Assert(!IsIdentical(SoftFloat.Zero, -SoftFloat.Zero)); 40 | Assert(IsIdentical(SoftFloat.NaN, float.NaN)); 41 | Assert(IsIdentical(SoftFloat.One, 1f)); 42 | Assert(IsIdentical(SoftFloat.MinusOne, -1f)); 43 | Assert(IsIdentical(SoftFloat.PositiveInfinity, float.PositiveInfinity)); 44 | Assert(IsIdentical(SoftFloat.NegativeInfinity, float.NegativeInfinity)); 45 | Assert(IsIdentical(SoftFloat.Epsilon, float.Epsilon)); 46 | Assert(IsIdentical(SoftFloat.MaxValue, float.MaxValue)); 47 | Assert(IsIdentical(SoftFloat.MinValue, float.MinValue)); 48 | } 49 | 50 | public void Equality() 51 | { 52 | Assert(SoftFloat.NaN != SoftFloat.NaN); 53 | Assert(SoftFloat.NaN.Equals(SoftFloat.NaN)); 54 | Assert(SoftFloat.Zero == -SoftFloat.Zero); 55 | Assert(SoftFloat.Zero.Equals(-SoftFloat.Zero)); 56 | Assert(!(SoftFloat.NaN > SoftFloat.Zero)); 57 | Assert(!(SoftFloat.NaN >= SoftFloat.Zero)); 58 | Assert(!(SoftFloat.NaN < SoftFloat.Zero)); 59 | Assert(!(SoftFloat.NaN <= SoftFloat.Zero)); 60 | Assert(SoftFloat.NaN.CompareTo(SoftFloat.Zero) == -1); 61 | Assert(SoftFloat.NaN.CompareTo(SoftFloat.NegativeInfinity) == -1); 62 | Assert(!(-SoftFloat.Zero < SoftFloat.Zero)); 63 | } 64 | 65 | 66 | public void Addition() 67 | { 68 | Assert(IsIdentical(SoftFloat.One + SoftFloat.One, 2f)); 69 | Assert(IsIdentical(SoftFloat.One - SoftFloat.One, 0f)); 70 | } 71 | 72 | public void Multiplication() 73 | { 74 | Assert(IsIdentical(SoftFloat.PositiveInfinity * SoftFloat.Zero, float.PositiveInfinity * 0f)); 75 | Assert(IsIdentical(SoftFloat.PositiveInfinity * (-SoftFloat.Zero), float.PositiveInfinity * (-0f))); 76 | Assert(IsIdentical(SoftFloat.PositiveInfinity * SoftFloat.One, float.PositiveInfinity * 1f)); 77 | Assert(IsIdentical(SoftFloat.PositiveInfinity * SoftFloat.MinusOne, float.PositiveInfinity * -1f)); 78 | 79 | Assert(IsIdentical(SoftFloat.NegativeInfinity * SoftFloat.Zero, float.NegativeInfinity * 0f)); 80 | Assert(IsIdentical(SoftFloat.NegativeInfinity * (-SoftFloat.Zero), float.NegativeInfinity * (-0f))); 81 | Assert(IsIdentical(SoftFloat.NegativeInfinity * SoftFloat.One, float.NegativeInfinity * 1f)); 82 | Assert(IsIdentical(SoftFloat.NegativeInfinity * SoftFloat.MinusOne, float.NegativeInfinity * -1f)); 83 | 84 | Assert(IsIdentical(SoftFloat.One * SoftFloat.One, 1f)); 85 | } 86 | 87 | public Tests() 88 | { 89 | Representation(); 90 | Equality(); 91 | Addition(); 92 | Multiplication(); 93 | } 94 | 95 | } 96 | } 97 | --------------------------------------------------------------------------------