Skip to content

Instantly share code, notes, and snippets.

@rzubek
Created July 3, 2019 18:41
Show Gist options
  • Save rzubek/2f7b223344b5283e794df9435dc774be to your computer and use it in GitHub Desktop.
Save rzubek/2f7b223344b5283e794df9435dc774be to your computer and use it in GitHub Desktop.
Very simple fixnum implementation for currency (dollars and cents)
using System;
using System.Collections.Generic;
using System.Globalization;
namespace SomaSim.Util
{
//
// very simple fixnum implementation that holds two digits after the decimal (so e.g. dollars and cents)
public struct Fixnum : IEquatable<Fixnum>, IComparable<Fixnum>
{
public static readonly Fixnum ZERO = new Fixnum();
public static readonly Fixnum MAX_VALUE = new Fixnum() { scaled = int.MaxValue };
public static readonly Fixnum MIN_VALUE = new Fixnum() { scaled = int.MinValue };
public const int SCALE = 100; // 2 digits = 10^2 = 100;
public int scaled; // raw representation without the decimal point
public Fixnum (int value) { scaled = value * SCALE; }
public Fixnum (float value) { scaled = (int)Math.Round(value * SCALE); }
public bool Equals (Fixnum other) => this.scaled == other.scaled;
public bool IsZero => this.scaled == ZERO.scaled;
public bool IsNotZero => this.scaled != ZERO.scaled;
public Fixnum Abs => (scaled >= 0) ? this : new Fixnum() { scaled = -scaled };
public Fixnum Floor() => new Fixnum() { scaled = SCALE * (int)Math.Floor((double)scaled / SCALE) };
public Fixnum Ceiling() => new Fixnum() { scaled = SCALE * (int)Math.Ceiling((double)scaled / SCALE) };
public override bool Equals (object obj) => obj is Fixnum && this.scaled == ((Fixnum)obj).scaled;
public override int GetHashCode () => scaled.GetHashCode();
public int CompareTo (Fixnum other) => this.scaled.CompareTo(other.scaled);
public static implicit operator Fixnum (int value) => new Fixnum(value);
public static explicit operator Fixnum (float value) => new Fixnum(value);
public static explicit operator int (Fixnum fixnum) => fixnum.scaled / SCALE;
public static explicit operator float (Fixnum fixnum) => fixnum.scaled / (float)SCALE;
public static bool operator == (Fixnum a, Fixnum b) => a.scaled == b.scaled;
public static bool operator != (Fixnum a, Fixnum b) => a.scaled != b.scaled;
public static bool operator < (Fixnum a, Fixnum b) => a.scaled < b.scaled;
public static bool operator > (Fixnum a, Fixnum b) => a.scaled > b.scaled;
public static bool operator <= (Fixnum a, Fixnum b) => a.scaled <= b.scaled;
public static bool operator >= (Fixnum a, Fixnum b) => a.scaled >= b.scaled;
public static Fixnum operator + (Fixnum f) => f;
public static Fixnum operator - (Fixnum f) => new Fixnum() { scaled = -f.scaled };
public static Fixnum operator + (Fixnum a, Fixnum b) => new Fixnum() { scaled = a.scaled + b.scaled };
public static Fixnum operator - (Fixnum a, Fixnum b) => new Fixnum() { scaled = a.scaled - b.scaled };
public static Fixnum operator * (Fixnum a, Fixnum b) {
long result = ((long)a.scaled * b.scaled) / SCALE;
return new Fixnum() { scaled = (int)result };
}
public static Fixnum operator / (Fixnum a, Fixnum b) {
long result = ((long)a.scaled * SCALE) / b.scaled;
return new Fixnum() { scaled = (int)result };
}
public static Fixnum Clamp (Fixnum value, Fixnum min, Fixnum max) {
if (value < min) { return min; }
if (value > max) { return max; }
return value;
}
public static Fixnum Max (Fixnum a, Fixnum b) => (a.scaled > b.scaled) ? a : b;
public static Fixnum Min (Fixnum a, Fixnum b) => (a.scaled < b.scaled) ? a : b;
public override string ToString () => ((float)this).ToString(CultureInfo.InvariantCulture);
}
public sealed class FixnumEqualityComparer : IEqualityComparer<Fixnum>
{
public bool Equals (Fixnum x, Fixnum y) { return x == y; }
public int GetHashCode (Fixnum obj) { return obj.GetHashCode(); }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment