popcorn/Scripts/Utilities/InfiniteFloat.cs

484 lines
14 KiB
C#

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;
}
}