/// <inheritdoc/> public bool TryCompile(IReadOnlyList <MathExpression> arguments, ICompilationContext <object?> context, ITypeHintHandler typeHintHandler, [MaybeNullWhen(false)] out Expression expr) { if (arguments.Count != 1) { expr = null; return(false); } var argExpr = context.Transform(arguments.First()); if (argExpr.Type == typeof(float) || argExpr.Type == typeof(double)) { // if this is a floating point var method = Helpers.GetMethod <Action <double> >(d => Math.Log(d)) !; expr = Expression.Call(method, CompilerHelpers.ConvertToType(argExpr, typeof(double))); return(true); } else if (CompilerHelpers.IsFloating(argExpr.Type) || CompilerHelpers.IsIntegral(argExpr.Type)) { // if this is a built-in integer or decimal var method = Helpers.GetMethod <Action <decimal> >(d => DecimalMath.Ln(d)) !; expr = Expression.Call(method, CompilerHelpers.ConvertToType(argExpr, typeof(decimal))); return(true); } expr = null; return(false); }
public void NaturalLog(decimal arg, decimal expect, decimal error) { var actual = DecimalMath.Ln(arg); var actualError = Math.Abs(expect - actual); Assert.True(error >= actualError, $"Error of {actualError}, expected no more than error of {error}"); }
/// <inheritdoc/> public override MathExpression ApplyTo(FunctionExpression expr, IOptimizationContext <object?> ctx, out bool transformResult) { if (!expr.IsUserDefined && (expr.Name == BuiltinFunctionExp.ConstName || expr.Name == BuiltinFunctionLn.ConstName)) { // exp(x) if (expr.Arguments.Count == 1) { var arg = ApplyTo(expr.Arguments.First(), ctx); if (arg is LiteralExpression lit) { transformResult = true; if (expr.Name == BuiltinFunctionExp.ConstName) { return(new LiteralExpression(DecimalMath.Exp(lit.Value)).WithToken(expr.Token)); } if (expr.Name == BuiltinFunctionLn.ConstName) { return(new LiteralExpression(DecimalMath.Ln(lit.Value)).WithToken(expr.Token)); } } } } return(base.ApplyTo(expr, ctx, out transformResult)); }
public void NaturalLogThrow(decimal arg) => Assert.Throws <OverflowException>(() => DecimalMath.Ln(arg));