/// <summary> /// Convert decimal to fraction /// </summary> /// <param name="value">decimal value to convert</param> /// <param name="result">result fraction if conversation is succsess</param> /// <param name="decimalPlaces">precision of considereation frac part of value</param> /// <param name="trimZeroes">trim zeroes on the right part of the value or not</param> /// <param name="minPeriodRepeat">minimum period repeating</param> /// <param name="digitsForReal">precision for determination value to real if period has not been founded</param> /// <returns></returns> public static bool FromDecimal(decimal value, out Rational <T> result, int decimalPlaces = 28, bool trimZeroes = false, decimal minPeriodRepeat = 2, int digitsForReal = 9) { var valueStr = value.ToString("0.0000000000000000000000000000", CultureInfo.InvariantCulture); var strs = valueStr.Split('.'); long intPart = long.Parse(strs[0]); string fracPartTrimEnd = strs[1].TrimEnd(new char[] { '0' }); string fracPart; if (trimZeroes) { fracPart = fracPartTrimEnd; decimalPlaces = Math.Min(decimalPlaces, fracPart.Length); } else { fracPart = strs[1]; } result = new Rational <T>(); try { string periodPart; bool periodFound = false; int i; for (i = 0; i < fracPart.Length; i++) { if (fracPart[i] == '0' && i != 0) { continue; } for (int j = i + 1; j < fracPart.Length; j++) { periodPart = fracPart.Substring(i, j - i); periodFound = true; decimal periodRepeat = 1; decimal periodStep = 1.0m / periodPart.Length; var upperBound = Math.Min(fracPart.Length, decimalPlaces); int k; for (k = i + periodPart.Length; k < upperBound; k += 1) { if (periodPart[(k - i) % periodPart.Length] != fracPart[k]) { periodFound = false; break; } periodRepeat += periodStep; } if (!periodFound && upperBound - k <= periodPart.Length && periodPart[(upperBound - i) % periodPart.Length] > '5') { var ind = (k - i) % periodPart.Length; var regroupedPeriod = (periodPart.Substring(ind) + periodPart.Remove(ind)).Substring(0, upperBound - k); ulong periodTailPlusOne = ulong.Parse(regroupedPeriod) + 1; ulong fracTail = ulong.Parse(fracPart.Substring(k, regroupedPeriod.Length)); if (periodTailPlusOne == fracTail) { periodFound = true; } } if (periodFound && periodRepeat >= minPeriodRepeat) { result = FromDecimal(strs[0], fracPart.Substring(0, i), periodPart); break; } else { periodFound = false; } } if (periodFound) { break; } } if (!periodFound) { result = new Rational <T>(long.Parse(strs[0]), 1, false); if (fracPartTrimEnd.Length != 0) { result += new Rational <T>(ulong.Parse(fracPartTrimEnd), TenInPower(fracPartTrimEnd.Length)); } return(fracPartTrimEnd.Length < digitsForReal); } return(true); } catch { return(false); } }
public ValueNode SimplifyValues(KnownFuncType?funcType, IList <ValueNode> args) { Rational <long> result; double temp = 0.0; switch (funcType) { case KnownFuncType.Add: result = args[0].Value; for (int i = 1; i < args.Count; i++) { result += args[i].Value; } return(new ValueNode(result)); case KnownFuncType.Sub: result = args[0].Value; for (int i = 1; i < args.Count; i++) { result -= args[i].Value; } return(new ValueNode(result)); case KnownFuncType.Mult: result = args[0].Value; for (int i = 1; i < args.Count; i++) { result *= args[i].Value; } return(new ValueNode(result)); case KnownFuncType.Div: result = args[0].Value; for (int i = 1; i < args.Count; i++) { result /= args[i].Value; } return(new ValueNode(result)); case KnownFuncType.Pow: if (args[1].Value.ToDouble() == 0.5) { temp = Math.Sqrt(args[0].Value.ToDouble()); } else { temp = Math.Pow(args[0].Value.ToDouble(), args[1].Value.ToDouble()); } break; case KnownFuncType.Neg: return(new ValueNode(-args[0].Value)); case KnownFuncType.Sgn: return(new ValueNode(new Rational <long>((long)Math.Sign(args[0].DoubleValue), 1, false))); case KnownFuncType.Trunc: return(new ValueNode(new Rational <long>((long)Math.Truncate(args[0].DoubleValue), 1, false))); case KnownFuncType.Round: return(new ValueNode(new Rational <long>((long)Math.Round(args[0].DoubleValue), 1, false))); case KnownFuncType.Diff: return(new ValueNode(0)); case KnownFuncType.Sqrt: temp = Math.Sqrt(args[0].DoubleValue); break; case KnownFuncType.Sin: temp = Math.Sin(args[0].DoubleValue); break; case KnownFuncType.Cos: temp = Math.Cos(args[0].DoubleValue); break; case KnownFuncType.Tan: temp = Math.Tan(args[0].DoubleValue); break; case KnownFuncType.Cot: temp = 1 / Math.Tan(args[0].DoubleValue); break; case KnownFuncType.Arcsin: temp = Math.Asin(args[0].DoubleValue); break; case KnownFuncType.Arccos: temp = Math.Acos(args[0].DoubleValue); break; case KnownFuncType.Arctan: temp = Math.Atan(args[0].DoubleValue); break; case KnownFuncType.Arccot: temp = Math.PI / 2 - Math.Atan(args[0].DoubleValue); break; case KnownFuncType.Sinh: temp = Math.Sinh(args[0].DoubleValue); break; case KnownFuncType.Cosh: temp = Math.Cosh(args[0].DoubleValue); break; case KnownFuncType.Arcsinh: temp = Math.Log(args[0].DoubleValue + Math.Sqrt(args[0].DoubleValue * args[0].DoubleValue + 1)); break; case KnownFuncType.Arcosh: temp = Math.Log(args[0].DoubleValue + Math.Sqrt(args[0].DoubleValue * args[0].DoubleValue - 1)); break; case KnownFuncType.Exp: temp = Math.Exp(args[0].DoubleValue); break; case KnownFuncType.Ln: temp = Math.Log(args[0].DoubleValue); break; case KnownFuncType.Log10: temp = Math.Log10(args[0].DoubleValue); break; case KnownFuncType.Log: temp = Math.Log(args[0].DoubleValue, args[1].DoubleValue); break; case KnownFuncType.Abs: temp = Math.Abs(args[0].DoubleValue); break; default: return(null); } try { if (Rational <long> .FromDecimal((decimal)temp, out result, 14, false, 4, 8)) { return(new ValueNode(result)); } } catch { } return(null); }
public CalculatedNode(Rational <long> value) { _value = (double)value.ToDecimal(CultureInfo.InvariantCulture); Name = _value.ToString(CultureInfo.InvariantCulture); }
private MathFuncNode MultValues(MathFuncNode funcNode) { var values = funcNode.Children .Where(child => child is ValueNode) .Cast <ValueNode>() .Select(valueChild => valueChild.Value); values = values.Concat(funcNode.Children .Where(child => child is FuncNode childFuncNode && childFuncNode.FunctionType == KnownFuncType.Neg) .Select(valueChild => new Rational <long>(-1, 1))); Rational <long> result = 1; foreach (var value in values) { result *= value; } if (result == 0) { return(new ValueNode(0)); } var notValuesNodes = funcNode.Children .Where(child => !(child is ValueNode) && !(child is FuncNode childFuncNode && childFuncNode.FunctionType == KnownFuncType.Neg)) .Concat(funcNode.Children .Where(child => child is FuncNode childFuncNode && childFuncNode.FunctionType == KnownFuncType.Neg) .Select(negChild => negChild.Children[0])).ToList(); if (result == 1) { return(notValuesNodes.Count == 0 ? new ValueNode(1) : notValuesNodes.Count == 1 ? notValuesNodes.First() : new FuncNode(KnownFuncType.Mult, notValuesNodes)); } else if (result == -1) { return(notValuesNodes.Count == 0 ? (MathFuncNode)(new ValueNode(-1)) : notValuesNodes.Count == 1 ? new FuncNode(KnownFuncType.Neg, notValuesNodes.First()) : new FuncNode(KnownFuncType.Neg, new FuncNode(KnownFuncType.Mult, notValuesNodes))); } else { if (notValuesNodes.Count == 0) { return(new ValueNode(result)); } else { if (result < 0) { notValuesNodes.Add(new ValueNode(-result)); return(new FuncNode(KnownFuncType.Neg, new FuncNode(KnownFuncType.Mult, notValuesNodes))); } else { notValuesNodes.Add(new ValueNode(result)); return(new FuncNode(KnownFuncType.Mult, notValuesNodes)); } } } }