{"id":1245,"date":"2015-10-13T22:23:36","date_gmt":"2015-10-14T05:23:36","guid":{"rendered":"http:\/\/www.elbeno.com\/blog\/?p=1245"},"modified":"2015-10-15T08:54:16","modified_gmt":"2015-10-15T15:54:16","slug":"more-constexpr-floating-point-computation","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=1245","title":{"rendered":"More constexpr floating-point computation"},"content":{"rendered":"<p>(Start at the <a href=\"https:\/\/www.elbeno.com\/blog\/?p=1206\">beginning of the series<\/a> &#8211; and all the source can be found in <a href=\"https:\/\/github.com\/elbeno\/constexpr\">my github repo<\/a>)<\/p>\n<p>In the <a href=\"https:\/\/www.elbeno.com\/blog\/?p=1211\">last post<\/a>, I covered my first forays into writing C++11-style <code>constexpr<\/code> floating point math functions. Once I&#8217;d done some trig functions, <code>exp<\/code>, and <code>floor<\/code> and friends, it seemed like the rest would be a piece of cake. Not entirely&#8230;<\/p>\n<p>But there was some easy stuff. With <code>trunc<\/code> sorted out, <code>fmod<\/code> was just:<\/p>\n<pre lang=\"cpp\">\r\nconstexpr float fmod(float x, float y)\r\n{\r\n  return y != 0 ? x - trunc(x\/y)*y :\r\n    throw err::fmod_domain_error;\r\n}\r\n<\/pre>\n<p>And <code>remainder<\/code> was very similar. Also, <code>fmax<\/code>, <code>fmin<\/code> and <code>fdim<\/code> were trivial: I won&#8217;t bore you with the code.<\/p>\n<p><strong>Euler was quite good at maths<\/strong><\/p>\n<p>Now I come from a games background, and there are a few maths functions that get used all the time in games. I already have <code>sqrt<\/code>. What I want now is <code>atan<\/code> and <code>atan2<\/code>. To warm up, I implemented the infinite series calculations for <code>asin<\/code> and <code>acos<\/code>, each of which are only defined for an input |x| <= 1. That was fairly straightforward, broadly in line with what I'd done before for the series expansions of <code>sin<\/code> and <code>cos<\/code>.<\/p>\n<p>Inverting <code>tan<\/code> was another matter: but a search revealed <a href=\"https:\/\/en.wikipedia.org\/wiki\/Inverse_trigonometric_functions#Relationships_among_the_inverse_trigonometric_functions\">a way to do it<\/a> using <code>asin<\/code>:<\/p>\n<p>[latex]arctan(x) = arcsin(\\frac{x}{\\sqrt{x^2+1}})[\/latex]<\/p>\n<p>Which I went with for a while. But then I <a href=\"https:\/\/en.wikipedia.org\/wiki\/Inverse_trigonometric_functions#Infinite_series\">spotted<\/a> the magic words:<\/p>\n<p>&#8220;Leonhard Euler found a more efficient series for the arctangent&#8221;<\/p>\n<p>[latex]arctan(z) = \\frac{z}{1+z^2} \\sum_{n=0}^{\\infty} \\prod_{k=1}^n \\frac{2kz^2}{(2k+1)(1+z^2)}[\/latex]<\/p>\n<p>More efficient (which I take here to mean more quickly converging)? And discovered by Euler? That&#8217;s good enough for me.<\/p>\n<pre lang=\"cpp\">\r\nnamespace detail\r\n{\r\n  template <typename T>\r\n  constexpr T atan_term(T x2, int k)\r\n  {\r\n    return (T{2}*static_cast<T>(k)*x2)\r\n      \/ ((T{2}*static_cast<T>(k)+T{1}) * (T{1}+x2));\r\n  }\r\n  template <typename T>\r\n  constexpr T atan_product(T x, int k)\r\n  {\r\n    return k == 1 ? atan_term(x*x, k) :\r\n      atan_term(x*x, k) * atan_product(x, k-1);\r\n  }\r\n  template <typename T>\r\n  constexpr T atan_sum(T x, T sum, int n)\r\n  {\r\n    return sum + atan_product(x, n) == sum ?\r\n      sum :\r\n      atan_sum(x, sum + atan_product(x, n), n+1);\r\n  }\r\n}\r\ntemplate <typename T>\r\nconstexpr T atan(T x)\r\n{\r\n  return true ?\r\n    x \/ (T{1} + x*x) * detail::atan_sum(x, T{1}, 1) :\r\n    throw err::atan_runtime_error;\r\n}\r\n<\/pre>\n<p>And <code>atan2<\/code> follows from <code>atan<\/code> relatively easily.<\/p>\n<p><strong>It&#8217;s big, it&#8217;s heavy, it&#8217;s wood<\/strong><\/p>\n<p>Looking over what I&#8217;d implemented so far, the next important function (and one that would serve as a building block for a few others) was <code>log<\/code>. So I programmed it using my friend the Taylor series expansion.<\/p>\n<p>Hm. It turns out that a naive implementation of <code>log<\/code> is quite slow to converge. (Yes, what a surprise.) OK, a bit of searching <a href=\"https:\/\/en.wikipedia.org\/wiki\/Natural_logarithm#High_precision\">yields fruit<\/a>: &#8220;&#8230; use Newton&#8217;s method to invert the exponentional function &#8230; the iteration simplifies to:&#8221;<\/p>\n<p>[latex]y_{n+1} = y_n + 2 \\frac{x &#8211; e^{y_n}}{x + e^{y_n}}[\/latex]<\/p>\n<p>&#8220;&#8230; which has cubic convergence to ln(x).&#8221;<\/p>\n<p>Result! I coded it up.<\/p>\n<pre lang=\"cpp\">\r\nnamespace detail\r\n{\r\n  template <typename T>\r\n  constexpr T log_iter(T x, T y)\r\n  {\r\n    return y + T{2} * (x - cx::exp(y)) \/ (x + cx::exp(y));\r\n  }\r\n  template <typename T>\r\n  constexpr T log(T x, T y)\r\n  {\r\n    return feq(y, log_iter(x, y)) ? y : log(x, log_iter(x, y));\r\n  }\r\n}\r\n<\/pre>\n<p>It worked well. A week or so later, <a href=\"http:\/\/nerds-central.blogspot.com\/2015\/09\/constexpr-of-natural-log-in-c11.html\">an article about C++11 constexpr log<\/a> surfaced serendipitously, and on reading it I realised my implementation wasn&#8217;t very well tested, so I added some tests. The tests revealed numerical instability for larger input values, so I took a tip from the article and used a couple of identities to constrain the input:<\/p>\n<p>[latex]ln(x) = ln(\\frac{x}{e}) + 1[\/latex]<br \/>\nand<br \/>\n[latex]ln(x) = ln(e.x) &#8211; 1[\/latex]<\/p>\n<p>Coding these expressions to constrain the input proper to <code>detail::log<\/code> seemed to solve the instability issues.<\/p>\n<p><strong>Are we done yet?<\/strong><\/p>\n<p>Now I was nearing the end of what I felt was a quorum of functions. To wit:<\/p>\n<ul>\n<li><code>sqrt<\/code>, <code>cbrt<\/code>, <code>hypot<\/code><\/li>\n<li><code>sin<\/code>, <code>cos<\/code>, <code>tan<\/code><\/li>\n<li><code>floor<\/code>, <code>ceil<\/code>, <code>trunc<\/code>, <code>round<\/code><\/li>\n<li><code>asin<\/code>, <code>acos<\/code>, <code>atan<\/code>, <code>atan2<\/code><\/li>\n<li><code>fmod<\/code>, <code>remainder<\/code><\/li>\n<li><code>exp<\/code>, <code>log<\/code>, <code>log2<\/code>, <code>log10<\/code><\/li>\n<\/ul>\n<p>With a decent implementation of <code>exp<\/code> and <code>log<\/code> it was easy to add the hyperbolic trig functions and their inverses. The only obviously missing function now was <code>pow<\/code>. Recall that I already had <code>ipow<\/code> for raising a floating-point value to an integral power, but I had been puzzling over a more general version of <code>pow<\/code> to allow raising to a floating-point power for a while. And then I suddenly realised the blindingly obvious:<\/p>\n<p>[latex]x^y = (e^{ln(x)})^y = e^{ln(x).y}[\/latex]<\/p>\n<p>And for the general case, <code>pow<\/code> was solved.<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T>\r\nconstexpr T pow(T x, T y)\r\n{\r\n  return true ? exp(log(x)*y) :\r\n    throw err::pow_runtime_error;\r\n}\r\n<\/pre>\n<p>I had now reached a satisfying conclusion to maths functions and I was getting fairly well-versed in writing <code>constexpr<\/code> code. Pausing only to implement <code>erf<\/code> (because why not?), I turned my attention now to <a href=\"https:\/\/www.elbeno.com\/blog\/?p=1254\">other <code>constexpr<\/code> matters<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(Start at the beginning of the series &#8211; and all the source can be found in my github repo) In the last post, I covered my first forays into writing C++11-style constexpr floating point math functions. Once I&#8217;d done some trig functions, exp, and floor and friends, it seemed like&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22],"tags":[],"class_list":["post-1245","post","type-post","status-publish","format-standard","hentry","category-cpp"],"_links":{"self":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1245","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1245"}],"version-history":[{"count":14,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1245\/revisions"}],"predecessor-version":[{"id":1302,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1245\/revisions\/1302"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1245"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1245"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1245"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}