using UnityEngine; using System; using System.Runtime.Serialization; [SerializableAttribute, DataContract] public struct InfiniteFloat { [DataMember] private float value; public float Value { get{ return value; } } [DataMember] private long index; public long Index { get{ return index; } } public InfiniteFloat(float value, long index = 0){ value *= Mathf.Pow(10.0f, index % 3); index -= index % 3; ToShorten(ref value, ref index); this.value = value; this.index = index; } public InfiniteFloat(ulong value){ this.index = 0; while(value > 1000000000){ value /= 1000; this.index += 3; } this.value = (float)value; ToShorten(ref this.value, ref this.index); } public static InfiniteFloat Zero { get{ return CreateInstance(0); } } public static InfiniteFloat One { get{ return CreateInstance(1); } } public void Reset(){ value = 0.0f; index = 0; } public static InfiniteFloat operator+(InfiniteFloat i1, InfiniteFloat i2){ if(i1.Index > i2.Index){ float value = i1.Value + i2.Value * Mathf.Pow(10.0f, i2.Index - i1.Index); return CreateInstance(value, i1.Index); }else if(i1.Index < i2.Index){ float value = i1.Value * Mathf.Pow(10.0f, i1.Index - i2.Index) + i2.Value; return CreateInstance(value, i2.Index); }else{ return CreateInstance(i1.Value + i2.Value, i1.Index); } } public static InfiniteFloat operator-(InfiniteFloat i1, InfiniteFloat i2){ if(i1.Index > i2.Index){ float value = i1.Value - i2.Value * Mathf.Pow(10.0f, i2.Index - i1.Index); return CreateInstance(value, i1.Index); }else if(i1.Index < i2.Index){ float value = i1.Value * Mathf.Pow(10.0f, i1.Index - i2.Index) - i2.Value; return CreateInstance(value, i2.Index); }else{ return CreateInstance(i1.Value - i2.Value, i1.Index); } } public static InfiniteFloat operator*(InfiniteFloat i1, InfiniteFloat i2){ return CreateInstance(i1.Value * i2.Value, i1.Index + i2.Index); } public static InfiniteFloat operator/(InfiniteFloat i1, InfiniteFloat i2){ return CreateInstance(i1.Value / i2.Value, i1.Index - i2.Index); } public static bool operator>(InfiniteFloat i1, InfiniteFloat i2){ if(i1.Index == i2.Index){ return i1.Value > i2.Value; }else if(i1.Index > i2.Index){ return true; }else { return false; } } public static bool operator>=(InfiniteFloat i1, InfiniteFloat i2){ if(i1.Index == i2.Index){ return i1.Value >= i2.Value; }else if(i1.Index > i2.Index){ return true; }else { return false; } } public static bool operator<(InfiniteFloat i1, InfiniteFloat i2){ if(i1.Index == i2.Index){ return i1.Value < i2.Value; }else if(i1.Index < i2.Index){ return true; }else { return false; } } public static bool operator<=(InfiniteFloat i1, InfiniteFloat i2){ if(i1.Index == i2.Index){ return i1.Value <= i2.Value; }else if(i1.Index < i2.Index){ return true; }else { return false; } } public static InfiniteFloat operator+(InfiniteFloat i, float f){ float value = i.Value + f * Mathf.Pow(10.0f, -i.Index); return CreateInstance(value, i.Index); } public static InfiniteFloat operator+(float f, InfiniteFloat i){ float value = f * Mathf.Pow(10.0f, -i.Index) + i.Value; return CreateInstance(value, i.Index); } public static InfiniteFloat operator-(InfiniteFloat i, float f){ float value = i.Value - f * Mathf.Pow(10.0f, -i.Index); return CreateInstance(value, i.Index); } public static InfiniteFloat operator-(float f, InfiniteFloat i){ float value = f * Mathf.Pow(10.0f, -i.Index) - i.Value; return CreateInstance(value, i.Index); } public static InfiniteFloat operator*(InfiniteFloat i, float f){ return CreateInstance(i.Value * f, i.Index); } public static InfiniteFloat operator*(float f, InfiniteFloat i){ return CreateInstance(f * i.Value, i.Index); } public static InfiniteFloat operator/(InfiniteFloat i, float f){ return CreateInstance(i.Value / f, i.Index); } public static InfiniteFloat operator/(float f, InfiniteFloat i){ return CreateInstance(f / i.Value, -i.Index); } public static bool operator>(InfiniteFloat i, float f){ return i.Value > f * Mathf.Pow(10.0f, -i.Index); } public static bool operator>(float f, InfiniteFloat i){ return f * Mathf.Pow(10.0f, -i.Index) > i.Value; } public static bool operator>=(InfiniteFloat i, float f){ return i.Value >= f * Mathf.Pow(10.0f, -i.Index); } public static bool operator>=(float f, InfiniteFloat i){ return f * Mathf.Pow(10.0f, -i.Index) >= i.Value; } public static bool operator<(InfiniteFloat i, float f){ return i.Value < f * Mathf.Pow(10.0f, -i.Index); } public static bool operator<(float f, InfiniteFloat i){ return f * Mathf.Pow(10.0f, -i.Index) < i.Value; } public static bool operator<=(InfiniteFloat i, float f){ return i.Value <= f * Mathf.Pow(10.0f, -i.Index); } public static bool operator<=(float f, InfiniteFloat i){ return f * Mathf.Pow(10.0f, -i.Index) <= i.Value; } public static InfiniteFloat operator*(InfiniteFloat i, double d){ long dIndex = 0; ToShorten(ref d, ref dIndex); return CreateInstance(i.Value * (float)d, i.Index + dIndex); } public static InfiniteFloat operator*(double d, InfiniteFloat i){ long dIndex = 0; ToShorten(ref d, ref dIndex); return CreateInstance((float)d * i.Value, dIndex + i.Index); } public static InfiniteFloat operator/(InfiniteFloat i, double d){ long dIndex = 0; ToShorten(ref d, ref dIndex); return CreateInstance(i.Value / (float)d, i.Index - dIndex); } public static InfiniteFloat operator/(double d, InfiniteFloat i){ long dIndex = 0; ToShorten(ref d, ref dIndex); return CreateInstance((float)d / i.Value, dIndex - i.Index); } public InfiniteFloat Pow(int p){ if(p > 0){ InfiniteFloat result = CreateInstance(value, index); for(int i = 1; i < p; ++i){ result *= this; } return result; }else if(p < 0){ InfiniteFloat result = CreateInstance(value, index); for(int i = 1; i < -p; ++i){ result *= this; } return 1.0f / result; }else{ return One; } } public InfiniteFloat Pow(float p){ return (this.Log() * p).Exp(); } public InfiniteFloat Sqrt(){ if(value < 0) return InfiniteFloat.Zero; if(index % 2 == 0){ return CreateInstance(Mathf.Sqrt(value), index >> 1); }else{ return CreateInstance(Mathf.Sqrt(value)) * CreateInstance(3.16227766017f, index >> 1); } } public InfiniteFloat Exp(){ var result = One + this; // とりあえず50 for(uint i = 2u; i <= 50u; ++i){ result += this.Pow((int)i) / Factorial(i); } return result; } public InfiniteFloat Log(){ // log(x) = a * 2 ^ n (1 <= a < 2) var a = this; int n = 0; while(a > 2.0f){ a = a / 2.0f; ++n; } // log(x) = log(a * 2 ^ n) // = log(a) + log(2 ^ n) // = log(a) + n * log(2) var right = n * 0.693147180559f; // log(a) -> log(y + 1) var y = a - 1.0f; // log(y + 1) = y - (y ^ 2 / 2) + (y ^ 3 / 3) - (y ^ 4 / 4) + (y ^ 5 / 5)... var left = y; // とりあえず50 for(int i = 2; i < 50; ++i){ if(i % 2 == 0){ left -= y.Pow(i) / i; }else{ left += y.Pow(i) / i; } } return left + right; } public static InfiniteFloat Factorial(uint i){ if(i == 0u){ return One; }else{ return i * Factorial(i - 1u); } } public InfiniteFloat Floor(){ if(index < 6){ return CreateInstance(Mathf.Floor(value * Mathf.Pow(10.0f, index)), 0); }else{ return CreateInstance(value, index); } } public int FloorToInt(){ InfiniteFloat v = Floor(); return (int)(v.Value * Mathf.Pow(10.0f, v.Index)); } private static void ToShorten(ref float value, ref long index){ if(float.IsInfinity(value)){ Debug.LogWarning("float value is Infinity."); value = 1.0f; }else if(float.IsNaN(value)){ Debug.LogWarning("float value is NaN."); value = 1.0f; } if(index > 0){ long rem = index % 3; if(rem > 0){ value *= Mathf.Pow(10.0f, rem); index -= rem; } } if(value > 0.0f){ while(value >= 1000.0f){ value *= 0.001f; index += 3; } while(value >= 10.0f && index < 0){ value *= 0.1f; ++index; } while(value < 1.0f && value > 0.0f && index > 0){ value *= 1000.0f; index -= 3; } while(value < 1.0f && value > 0.0f && index <= 0){ value *= 10.0f; --index; } }else if(value < 0.0f){ while(value <= -1000.0f){ value *= 0.001f; index += 3; } while(value <= -10.0f && index < 0){ value *= 0.1f; ++index; } while(value > -1.0f && value < 0.0f && index > 0){ value *= 1000.0f; index -= 3; } while(value > -1.0f && value < 0.0f && index <= 0){ value *= 10.0f; --index; } }else{ index = 0; } if(index > 0){ long rem = index % 3; if(rem > 0){ value *= Mathf.Pow(10.0f, rem); index -= rem; } } } private static void ToShorten(ref double value, ref long index){ if(double.IsInfinity(value)){ Debug.LogWarning("double value is Infinity."); value = 1.0; }else if(double.IsNaN(value)){ Debug.LogWarning("double value is NaN."); value = 1.0; } if(value >= 0.0){ while(value >= 1000.0){ value *= 0.001; index += 3; } while(value < 1.0 && value > 0.0){ value *= 10.0; --index; } }else{ while(value <= -1000.0){ value *= 0.001; index += 3; } while(value > -1.0 && value < 0.0){ value *= 10.0; --index; } } } public static InfiniteFloat CreateInstance(float value, long index = 0){ ToShorten(ref value, ref index); InfiniteFloat result; result.value = value; result.index = index; return result; } private static readonly string[] unit = new string[] { "", "K", "M", "B", "T", "Q" }; public override string ToString(){ return _ToString(unit, false, 1, 3); } public string ToString(string[] unit){ return _ToString(unit, false, 1, 3); } public string ToString(uint decimalCount = 1, int minIndex = 3){ return _ToString(unit, false, decimalCount, minIndex); } public string ToStringInt(uint decimalCount = 1, int minIndex = 3){ return _ToString(unit, true, decimalCount, minIndex); } private string _ToString(string[] unit, bool isInt, uint decimalCount, int minIndex){ float v = value; long i = index; while(v >= 10.0f || v <= -10.0f){ v *= 0.1f; ++i; } if(i >= minIndex){ long u = index / 3; if(u < unit.Length){ return string.Format("{0}{1}", value.Floor(decimalCount).ToString(string.Format("N{0}", decimalCount)), unit[u]); }else{ return string.Format("{0}e{1}", v.Floor(decimalCount).ToString(string.Format("N{0}", decimalCount)), i); } }else if(index < 0){ if(isInt){ return 0.ToString(); }else{ return string.Format("{0:F2}e{1}", value.Floor(2), index); } }else{ if(isInt){ return string.Format("{0:N0}", (value * Mathf.Pow(10.0f, index)).Floor(1)); }else{ return (value * Mathf.Pow(10.0f, index)).Floor(decimalCount).ToString(string.Format("N{0}", decimalCount)); } } } private static readonly string[] unitC = new string[] { "", "万", "億", "兆", "京", "垓", "秭", "穣", "溝", "澗", "正", "載", "極" }; public string ToChineseNumerals(){ return ToChineseNumerals(unitC, unitC[unitC.Length - 1]); } public string ToChineseNumerals(string[] unit, string lastUnit){ return _ToChineseNumerals("{0:F1}", unit, lastUnit, false); } public string ToChineseNumeralsInt(){ return ToChineseNumeralsInt(unitC, unitC[unitC.Length - 1]); } public string ToChineseNumeralsInt(string[] unit, string lastUnit){ return _ToChineseNumerals("{0:F0}", unit, lastUnit, true); } private string _ToChineseNumerals(string zeroIndexFormat, string[] unit, string lastUnit, bool isInt){ if(index > 0){ long u = index / 4; long keta = index % 4; float v = value; while(v >= 10.0f || v <= -10.0f){ v *= 0.1f; ++keta; } while(keta >= 4){ keta -= 4; ++u; } if(u < unit.Length){ if(u == 0){ return string.Format(zeroIndexFormat, Mathf.Floor(v * Mathf.Pow(10.0f, keta) * 10.0f) * 0.1f); }else{ return string.Format("{0:F1}{1}", Mathf.Floor(v * Mathf.Pow(10.0f, keta) * 10.0f) * 0.1f, unit[u]); } }else{ v = value; long i = index; while(v >= 10.0f || v <= -10.0f){ v *= 0.1f; ++i; } i -= unitC.Length * 4 - 1; // lastUnitが指数表記出ない場合使用 return string.Format("{0:F2}{1}+{2}", v.Floor(2), lastUnit, i); } }else if(index < 0){ if(isInt){ return string.Format(zeroIndexFormat, 0); }else{ return string.Format("{0:F1}{1}+{2}", value.Floor(1), lastUnit, index); } }else{ return string.Format(zeroIndexFormat, value.Floor(1)); } } public float ToFloat(){ return value * Mathf.Pow(10.0f, index); } public ulong ToULong(){ if(index <= 6){ return (ulong)(value * Mathf.Pow(10.0f, index)); }else{ ulong result = (ulong)(value * Mathf.Pow(10.0f, 6)); for(int i = 0; i < index - 6; ++i){ result *= 10; } return result; } } public static InfiniteFloat Lerp(InfiniteFloat a, InfiniteFloat b, float t){ return a + (b - a) * t; } }