using System; using System.Collections.Generic; using System.Text; namespace NetGoods { public struct Currency : IComparable, IFormattable, IConvertible, IComparable, IEquatable { private long value; private const byte multiplier=100; public Currency(Object value) { this.value = (long)Math.Round(Convert.ToDouble(value) * multiplier, 2); } public Currency(Double value) { this.value = (long)Math.Round(value * multiplier, 2); } public Currency(long high, byte low) { if (low < 0 || low > (multiplier-1)) throw new ArgumentException(); if (high >= 0) value = multiplier * high + low; else value = multiplier * high - low; } private Currency(long value) { this.value = value * multiplier; } private Currency(long value, int digits) { this.value = value * digits; } // Количество рублей public long High { get { return value / multiplier; } } // Количество копеек public byte Low { get { return (byte)(value % multiplier); } } // Деление на одинаковые части // Количество частей должно быть не меньше 2 public Currency[] Share(uint n) { if (n < 2) throw new ArgumentException(); Currency lowResult = new Currency(value / n); Currency highResult = lowResult.value >= 0 ? new Currency(lowResult.value + 1) : new Currency(lowResult.value - 1); Currency[] results = new Currency[n]; long remainder = Math.Abs(value % n); for (long i = 0; i < remainder; i++) results[i] = highResult; for (long i = remainder; i < n; i++) results[i] = lowResult; return results; } // Деление пропорционально коэффициентам // Количество коэффициентов должно быть не меньше 2 public Currency[] Allocate(params uint[] ratios) { if (ratios.Length < 2) throw new ArgumentException(); long total = 0; for (int i = 0; i < ratios.Length; i++) total += ratios[i]; long remainder = value; Currency[] results = new Currency[ratios.Length]; for (int i = 0; i < results.Length; i++) { results[i] = new Currency(value * ratios[i] / total); remainder -= results[i].value; } if (remainder > 0) for (int i = 0; i < remainder; i++) results[i].value++; else for (int i = 0; i > remainder; i--) results[i].value--; return results; } public override bool Equals(object obj) { try { return this == (Currency) obj; } catch { return false; } } public bool Equals(Currency obj) { return this == obj; ; } public override int GetHashCode() { return value.GetHashCode(); } #region Операции public static implicit operator double(Currency a) { return (double)a.value / multiplier; } public static implicit operator int(Currency a) { return (int)a.High; } public static implicit operator long(Currency a) { return (long)a.High; } public static explicit operator Currency(double a) { return new Currency(a); } public static explicit operator Currency(long a) { return new Currency(a); } /*public static explicit operator Currency(object a) { return new Currency((double) a); }*/ public static bool operator ==(Currency a, Currency b) { return a.value == b.value; } public static bool operator !=(Currency a, Currency b) { return a.value != b.value; } public static bool operator >(Currency a, Currency b) { return a.value > b.value; } public static bool operator >=(Currency a, Currency b) { return a.value >= b.value; } public static bool operator <(Currency a, Currency b) { return a.value < b.value; } public static bool operator <=(Currency a, Currency b) { return a.value <= b.value; } public static Currency operator *(Currency a, Currency b) { return new Currency(a.value * b.value, (int)1); } public static Currency operator /(Currency a, Currency b) { return new Currency(a.value / b.value, (int)Currency.multiplier); } public static Currency operator -(Currency a, Currency b) { return new Currency(a.value - b.value, (int)1); } public static Currency operator +(Currency a, Currency b) { return new Currency(a.value + b.value, (int)1); } public static Currency operator ++(Currency a) { return new Currency(a.value++, (int)1); } public static Currency operator --(Currency a) { return new Currency(a.value--, (int)1); } public static Currency operator %(Currency a, Currency b) { return new Currency(a.value % b.value, (int)1); } #endregion #region IFormattable Members public override string ToString() { if (this.Low < 10) return (this.High.ToString() + ",0" + this.Low.ToString()); else return (this.High.ToString() + "," + this.Low.ToString()); } public string ToString(IFormatProvider formatProvider) { return ((double)this).ToString(formatProvider); } public string ToString(string format) { return ((double)this).ToString(format); } string IFormattable.ToString(string format, IFormatProvider formatProvider) { return ((double)this).ToString(format, formatProvider); } #endregion #region IComparable Members public int CompareTo(object obj) { if (value < ((Currency)obj).value) return -1; else if (value == ((Currency)obj).value) return 0; else return 1; } public int CompareTo(Currency obj) { if (value < obj.value) return -1; else if (value == obj.value) return 0; else return 1; } #endregion #region IConvertible Members TypeCode IConvertible.GetTypeCode() { return this.value.GetTypeCode(); } bool IConvertible.ToBoolean(IFormatProvider provider) { return (this.value != 0); } byte IConvertible.ToByte(IFormatProvider provider) { return (byte)this.High; } char IConvertible.ToChar(IFormatProvider provider) { return (char)this.High; } DateTime IConvertible.ToDateTime(IFormatProvider provider) { return Convert.ToDateTime((this.value / 100), provider); } decimal IConvertible.ToDecimal(IFormatProvider provider) { return (this.value / 100); } double IConvertible.ToDouble(IFormatProvider provider) { return (this.value / 100); } short IConvertible.ToInt16(IFormatProvider provider) { return (short)(this.value / 100); } int IConvertible.ToInt32(IFormatProvider provider) { return (int)this.High; } long IConvertible.ToInt64(IFormatProvider provider) { return this.High; } sbyte IConvertible.ToSByte(IFormatProvider provider) { return (sbyte)this.High; } float IConvertible.ToSingle(IFormatProvider provider) { return (this.value / 100); } object IConvertible.ToType(Type conversionType, IFormatProvider provider) { return Convert.ChangeType((this.value / 100), conversionType); } ushort IConvertible.ToUInt16(IFormatProvider provider) { return (ushort)this.High; } uint IConvertible.ToUInt32(IFormatProvider provider) { return (uint)this.High; } ulong IConvertible.ToUInt64(IFormatProvider provider) { return (ulong)this.High; } string IConvertible.ToString(IFormatProvider provider) { return this.ToString(provider); } #endregion } }