New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
added log and log1p functions #225
Changes from all commits
3e8722f
f6d6f06
1532e02
7175bbf
a350e1e
e1fca7b
a6d2046
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
include LICENSE | ||
recursive-include m2cgen VERSION.txt | ||
recursive-include m2cgen linear_algebra.* | ||
recursive-include m2cgen log1p.* | ||
recursive-include m2cgen tanh.* | ||
global-exclude *.py[cod] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
private static double Log1p(double x) { | ||
if (x == 0.0) | ||
return 0.0; | ||
if (x == -1.0) | ||
return double.NegativeInfinity; | ||
if (x < -1.0) | ||
return double.NaN; | ||
double xAbs = Abs(x); | ||
if (xAbs < 0.5 * double.Epsilon) | ||
return x; | ||
if ((x > 0.0 && x < 1e-8) || (x > -1e-9 && x < 0.0)) | ||
return x * (1.0 - x * 0.5); | ||
if (xAbs < 0.375) { | ||
double[] coeffs = { | ||
0.10378693562743769800686267719098e+1, | ||
-0.13364301504908918098766041553133e+0, | ||
0.19408249135520563357926199374750e-1, | ||
-0.30107551127535777690376537776592e-2, | ||
0.48694614797154850090456366509137e-3, | ||
-0.81054881893175356066809943008622e-4, | ||
0.13778847799559524782938251496059e-4, | ||
-0.23802210894358970251369992914935e-5, | ||
0.41640416213865183476391859901989e-6, | ||
-0.73595828378075994984266837031998e-7, | ||
0.13117611876241674949152294345011e-7, | ||
-0.23546709317742425136696092330175e-8, | ||
0.42522773276034997775638052962567e-9, | ||
-0.77190894134840796826108107493300e-10, | ||
0.14075746481359069909215356472191e-10, | ||
-0.25769072058024680627537078627584e-11, | ||
0.47342406666294421849154395005938e-12, | ||
-0.87249012674742641745301263292675e-13, | ||
0.16124614902740551465739833119115e-13, | ||
-0.29875652015665773006710792416815e-14, | ||
0.55480701209082887983041321697279e-15, | ||
-0.10324619158271569595141333961932e-15}; | ||
return x * (1.0 - x * ChebyshevBroucke(x / 0.375, coeffs)); | ||
} | ||
return Log(1.0 + x); | ||
} | ||
private static double ChebyshevBroucke(double x, double[] coeffs) { | ||
double b0, b1, b2, x2; | ||
b2 = b1 = b0 = 0.0; | ||
x2 = x * 2; | ||
for (int i = coeffs.Length - 1; i >= 0; --i) { | ||
b2 = b1; | ||
b1 = b0; | ||
b0 = x2 * b1 - b2 + coeffs[i]; | ||
} | ||
return (b0 - b2) * 0.5; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
double log1p(double x) { | ||
if (x == 0.0) | ||
return 0.0; | ||
if (x == -1.0) | ||
return double.negativeInfinity; | ||
if (x < -1.0) | ||
return double.nan; | ||
double xAbs = x.abs(); | ||
if (xAbs < 0.5 * 4.94065645841247e-324) | ||
return x; | ||
if ((x > 0.0 && x < 1e-8) || (x > -1e-9 && x < 0.0)) | ||
return x * (1.0 - x * 0.5); | ||
if (xAbs < 0.375) { | ||
List<double> coeffs = [ | ||
0.10378693562743769800686267719098e+1, | ||
-0.13364301504908918098766041553133e+0, | ||
0.19408249135520563357926199374750e-1, | ||
-0.30107551127535777690376537776592e-2, | ||
0.48694614797154850090456366509137e-3, | ||
-0.81054881893175356066809943008622e-4, | ||
0.13778847799559524782938251496059e-4, | ||
-0.23802210894358970251369992914935e-5, | ||
0.41640416213865183476391859901989e-6, | ||
-0.73595828378075994984266837031998e-7, | ||
0.13117611876241674949152294345011e-7, | ||
-0.23546709317742425136696092330175e-8, | ||
0.42522773276034997775638052962567e-9, | ||
-0.77190894134840796826108107493300e-10, | ||
0.14075746481359069909215356472191e-10, | ||
-0.25769072058024680627537078627584e-11, | ||
0.47342406666294421849154395005938e-12, | ||
-0.87249012674742641745301263292675e-13, | ||
0.16124614902740551465739833119115e-13, | ||
-0.29875652015665773006710792416815e-14, | ||
0.55480701209082887983041321697279e-15, | ||
-0.10324619158271569595141333961932e-15]; | ||
return x * (1.0 - x * chebyshevBroucke(x / 0.375, coeffs)); | ||
} | ||
return log(1.0 + x); | ||
} | ||
double chebyshevBroucke(double x, List<double> coeffs) { | ||
double b0, b1, b2, x2; | ||
b2 = b1 = b0 = 0.0; | ||
x2 = x * 2; | ||
for (int i = coeffs.length - 1; i >= 0; --i) { | ||
b2 = b1; | ||
b1 = b0; | ||
b0 = x2 * b1 - b2 + coeffs[i]; | ||
} | ||
return (b0 - b2) * 0.5; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
log1p :: Double -> Double | ||
log1p x | ||
| x == 0 = 0 | ||
| x == -1 = -1 / 0 | ||
| x < -1 = 0 / 0 | ||
| x' < m_epsilon * 0.5 = x | ||
| (x > 0 && x < 1e-8) || (x > -1e-9 && x < 0) | ||
= x * (1 - x * 0.5) | ||
| x' < 0.375 = x * (1 - x * chebyshevBroucke (x / 0.375) coeffs) | ||
| otherwise = log (1 + x) | ||
where | ||
m_epsilon = encodeFloat (signif + 1) expo - 1.0 | ||
where (signif, expo) = decodeFloat (1.0::Double) | ||
x' = abs x | ||
coeffs = [0.10378693562743769800686267719098e+1, | ||
-0.13364301504908918098766041553133e+0, | ||
0.19408249135520563357926199374750e-1, | ||
-0.30107551127535777690376537776592e-2, | ||
0.48694614797154850090456366509137e-3, | ||
-0.81054881893175356066809943008622e-4, | ||
0.13778847799559524782938251496059e-4, | ||
-0.23802210894358970251369992914935e-5, | ||
0.41640416213865183476391859901989e-6, | ||
-0.73595828378075994984266837031998e-7, | ||
0.13117611876241674949152294345011e-7, | ||
-0.23546709317742425136696092330175e-8, | ||
0.42522773276034997775638052962567e-9, | ||
-0.77190894134840796826108107493300e-10, | ||
0.14075746481359069909215356472191e-10, | ||
-0.25769072058024680627537078627584e-11, | ||
0.47342406666294421849154395005938e-12, | ||
-0.87249012674742641745301263292675e-13, | ||
0.16124614902740551465739833119115e-13, | ||
-0.29875652015665773006710792416815e-14, | ||
0.55480701209082887983041321697279e-15, | ||
-0.10324619158271569595141333961932e-15] | ||
chebyshevBroucke i = fini . foldr step [0, 0, 0] | ||
where | ||
step k [b0, b1, _] = [(k + i * 2 * b0 - b1), b0, b1] | ||
fini [b0, _, b2] = (b0 - b2) * 0.5 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -83,6 +83,8 @@ class ToCodeInterpreter(BaseToCodeInterpreter): | |
|
||
abs_function_name = NotImplemented | ||
exponent_function_name = NotImplemented | ||
logarithm_function_name = NotImplemented | ||
log1p_function_name = NotImplemented | ||
power_function_name = NotImplemented | ||
sqrt_function_name = NotImplemented | ||
tanh_function_name = NotImplemented | ||
|
@@ -140,6 +142,23 @@ def interpret_exp_expr(self, expr, **kwargs): | |
return self._cg.function_invocation( | ||
self.exponent_function_name, nested_result) | ||
|
||
def interpret_log_expr(self, expr, **kwargs): | ||
if self.logarithm_function_name is NotImplemented: | ||
raise NotImplementedError("Logarithm function is not provided") | ||
self.with_math_module = True | ||
nested_result = self._do_interpret(expr.expr, **kwargs) | ||
return self._cg.function_invocation( | ||
self.logarithm_function_name, nested_result) | ||
|
||
def interpret_log1p_expr(self, expr, **kwargs): | ||
self.with_math_module = True | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe we should set this flag only in case when we don't follow the fallback path. In case of the fallback we technically don't require the math module, although subsequent expressions that constitute the fallback expression may choose to enable it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Thanks! Actually it was not so hard. All imperative languages are so similar! 😄
Sorry, I'm not sure I fully understood you. Do you mean the following?
If so, it seems reasonable for me. But we should double check cases when fallbacks use functions from math module. Anyway, I believe that this should be addressed in a separate PR because all other expressions follow the same pattern for now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this is exactly what I mean!
Yep, but those functions will also be interpreted and the flag will be set accordingly if needed.
I'm fine with that. We may want to address this for other functions as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! I created new issue for that to not forget: #246. |
||
if self.log1p_function_name is NotImplemented: | ||
return self._do_interpret( | ||
fallback_expressions.log1p(expr.expr), **kwargs) | ||
nested_result = self._do_interpret(expr.expr, **kwargs) | ||
return self._cg.function_invocation( | ||
self.log1p_function_name, nested_result) | ||
|
||
def interpret_sqrt_expr(self, expr, **kwargs): | ||
self.with_math_module = True | ||
if self.sqrt_function_name is NotImplemented: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, I didn't find anything that we could use as a fallback expression for
LogExpr
. All methods are based on reduction technique which requiresfrexp
implementation.Refer for example to https://golang.org/src/math/log.go