changeset 16616:2f2ef742aa4b

New module 'exp2'. * lib/math.in.h (exp2): New declaration. * lib/exp2.c: New file. * m4/exp2.m4: New file. * m4/math_h.m4 (gl_MATH_H): Test whether exp2 is declared. (gl_MATH_H_DEFAULTS): Initialize GNULIB_EXP2, HAVE_DECL_EXP2, REPLACE_EXP2. * modules/math (Makefile.am): Substitute GNULIB_EXP2, HAVE_DECL_EXP2, REPLACE_EXP2. * modules/exp2: New file. * tests/test-math-c++.cc: Check the declaration of exp2. * doc/posix-functions/exp2.texi: Mention the new module and the IRIX and OpenBSD problems.
author Bruno Haible <bruno@clisp.org>
date Wed, 07 Mar 2012 03:29:32 +0100
parents 3ecaf6d77eca
children 927dd3ecbb9e
files ChangeLog doc/posix-functions/exp2.texi lib/exp2.c lib/math.in.h m4/exp2.m4 m4/math_h.m4 modules/exp2 modules/math tests/test-math-c++.cc
diffstat 9 files changed, 628 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2012-03-08  Bruno Haible  <bruno@clisp.org>
+
+        New module 'exp2'.
+        * lib/math.in.h (exp2): New declaration.
+        * lib/exp2.c: New file.
+        * m4/exp2.m4: New file.
+        * m4/math_h.m4 (gl_MATH_H): Test whether exp2 is declared.
+        (gl_MATH_H_DEFAULTS): Initialize GNULIB_EXP2, HAVE_DECL_EXP2,
+        REPLACE_EXP2.
+        * modules/math (Makefile.am): Substitute GNULIB_EXP2, HAVE_DECL_EXP2,
+        REPLACE_EXP2.
+        * modules/exp2: New file.
+        * tests/test-math-c++.cc: Check the declaration of exp2.
+        * doc/posix-functions/exp2.texi: Mention the new module and the IRIX
+        and OpenBSD problems.
+
 2012-03-08  Paul Eggert  <eggert@cs.ucla.edu>
 
 	savedir: fix comment typo
--- a/doc/posix-functions/exp2.texi
+++ b/doc/posix-functions/exp2.texi
@@ -4,15 +4,21 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/exp2.html}
 
-Gnulib module: ---
+Gnulib module: exp2
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function is missing on some platforms:
+FreeBSD 5.2.1, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, older IRIX 6.5, OSF/1 4.0, Solaris 9, MSVC 9, Interix 3.5.
+@item
+This function is not declared on some platforms:
+IRIX 6.5.
+@item
+This function returns grossly wrong results on some platforms:
+OpenBSD 4.9.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-This function is missing on some platforms:
-FreeBSD 5.2.1, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, IRIX 6.5, OSF/1 4.0, Solaris 9, MSVC 9, Interix 3.5.
 @end itemize
new file mode 100644
--- /dev/null
+++ b/lib/exp2.c
@@ -0,0 +1,387 @@
+/* Exponential base 2 function.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <math.h>
+
+#include <float.h>
+
+/* Best possible approximation of log(2) as a 'double'.  */
+#define LOG2 0.693147180559945309417232121458176568075
+
+/* Best possible approximation of 1/log(2) as a 'double'.  */
+#define LOG2_INVERSE 1.44269504088896340735992468100189213743
+
+/* Best possible approximation of log(2)/256 as a 'double'.  */
+#define LOG2_BY_256 0.00270760617406228636491106297444600221904
+
+/* Best possible approximation of 256/log(2) as a 'double'.  */
+#define LOG2_BY_256_INVERSE 369.329930467574632284140718336484387181
+
+double
+exp2 (double x)
+{
+  /* exp2(x) = exp(x*log(2)).
+     If we would compute it like this, there would be rounding errors for
+     integer or near-integer values of x.  To avoid these, we inline the
+     algorithm for exp(), and the multiplication with log(2) cancels a
+     division by log(2).  */
+
+  if (isnand (x))
+    return x;
+
+  if (x > (double) DBL_MAX_EXP)
+    /* x > DBL_MAX_EXP
+       hence exp2(x) > 2^DBL_MAX_EXP, overflows to Infinity.  */
+    return HUGE_VAL;
+
+  if (x < (double) (DBL_MIN_EXP - 1 - DBL_MANT_DIG))
+    /* x < (DBL_MIN_EXP - 1 - DBL_MANT_DIG)
+       hence exp2(x) < 2^(DBL_MIN_EXP-1-DBL_MANT_DIG),
+       underflows to zero.  */
+    return 0.0;
+
+  /* Decompose x into
+       x = n + m/256 + y/log(2)
+     where
+       n is an integer,
+       m is an integer, -128 <= m <= 128,
+       y is a number, |y| <= log(2)/512 + epsilon = 0.00135...
+     Then
+       exp2(x) = 2^n * exp(m * log(2)/256) * exp(y)
+     The first factor is an ldexpl() call.
+     The second factor is a table lookup.
+     The third factor is computed
+     - either as sinh(y) + cosh(y)
+       where sinh(y) is computed through the power series:
+         sinh(y) = y + y^3/3! + y^5/5! + ...
+       and cosh(y) is computed as hypot(1, sinh(y)),
+     - or as exp(2*z) = (1 + tanh(z)) / (1 - tanh(z))
+       where z = y/2
+       and tanh(z) is computed through its power series:
+         tanh(z) = z
+                   - 1/3 * z^3
+                   + 2/15 * z^5
+                   - 17/315 * z^7
+                   + 62/2835 * z^9
+                   - 1382/155925 * z^11
+                   + 21844/6081075 * z^13
+                   - 929569/638512875 * z^15
+                   + ...
+       Since |z| <= log(2)/1024 < 0.0007, the relative error of the z^7 term
+       is < 0.0007^6 < 2^-60 <= 2^-DBL_MANT_DIG, therefore we can truncate
+       the series after the z^5 term.  */
+
+  {
+    double nm = round (x * 256.0); /* = 256 * n + m */
+    double z = (x * 256.0 - nm) * (LOG2_BY_256 * 0.5);
+
+/* Coefficients of the power series for tanh(z).  */
+#define TANH_COEFF_1   1.0
+#define TANH_COEFF_3  -0.333333333333333333333333333333333333334
+#define TANH_COEFF_5   0.133333333333333333333333333333333333334
+#define TANH_COEFF_7  -0.053968253968253968253968253968253968254
+#define TANH_COEFF_9   0.0218694885361552028218694885361552028218
+#define TANH_COEFF_11 -0.00886323552990219656886323552990219656886
+#define TANH_COEFF_13  0.00359212803657248101692546136990581435026
+#define TANH_COEFF_15 -0.00145583438705131826824948518070211191904
+
+    double z2 = z * z;
+    double tanh_z =
+      ((TANH_COEFF_5
+        * z2 + TANH_COEFF_3)
+       * z2 + TANH_COEFF_1)
+      * z;
+
+    double exp_y = (1.0 + tanh_z) / (1.0 - tanh_z);
+
+    int n = (int) round (nm * (1.0 / 256.0));
+    int m = (int) nm - 256 * n;
+
+    /* exp_table[i] = exp((i - 128) * log(2)/256).
+       Computed in GNU clisp through
+         (setf (long-float-digits) 128)
+         (setq a 0L0)
+         (setf (long-float-digits) 256)
+         (dotimes (i 257)
+           (format t "        ~D,~%"
+                   (float (exp (* (/ (- i 128) 256) (log 2L0))) a)))  */
+    static const double exp_table[257] =
+      {
+        0.707106781186547524400844362104849039284,
+        0.709023942160207598920563322257676190836,
+        0.710946301084582779904674297352120049962,
+        0.71287387205274715340350157671438300618,
+        0.714806669195985005617532889137569953044,
+        0.71674470668389442125974978427737336719,
+        0.71868799872449116280161304224785251353,
+        0.720636559564312831364255957304947586072,
+        0.72259040348852331001850312073583545284,
+        0.724549544821017490259402705487111270714,
+        0.726513997924526282423036245842287293786,
+        0.728483777200721910815451524818606761737,
+        0.730458897090323494325651445155310766577,
+        0.732439372073202913296664682112279175616,
+        0.734425216668490963430822513132890712652,
+        0.736416445434683797507470506133110286942,
+        0.738413072969749655693453740187024961962,
+        0.740415113911235885228829945155951253966,
+        0.742422582936376250272386395864403155277,
+        0.744435494762198532693663597314273242753,
+        0.746453864145632424600321765743336770838,
+        0.748477705883617713391824861712720862423,
+        0.750507034813212760132561481529764324813,
+        0.752541865811703272039672277899716132493,
+        0.75458221379671136988300977551659676571,
+        0.756628093726304951096818488157633113612,
+        0.75867952059910734940489114658718937343,
+        0.760736509454407291763130627098242426467,
+        0.762799075372269153425626844758470477304,
+        0.76486723347364351194254345936342587308,
+        0.766940998920478000900300751753859329456,
+        0.769020386915828464216738479594307884331,
+        0.771105412703970411806145931045367420652,
+        0.773196091570510777431255778146135325272,
+        0.77529243884249997956151370535341912283,
+        0.777394469888544286059157168801667390437,
+        0.779502200118918483516864044737428940745,
+        0.781615644985678852072965367573877941354,
+        0.783734819982776446532455855478222575498,
+        0.78585974064617068462428149076570281356,
+        0.787990422553943243227635080090952504452,
+        0.790126881326412263402248482007960521995,
+        0.79226913262624686505993407346567890838,
+        0.794417192158581972116898048814333564685,
+        0.796571075671133448968624321559534367934,
+        0.798730798954313549131410147104316569576,
+        0.800896377841346676896923120795476813684,
+        0.803067828208385462848443946517563571584,
+        0.805245165974627154089760333678700291728,
+        0.807428407102430320039984581575729114268,
+        0.809617567597431874649880866726368203972,
+        0.81181266350866441589760797777344082227,
+        0.814013710928673883424109261007007338614,
+        0.816220725993637535170713864466769240053,
+        0.818433724883482243883852017078007231025,
+        0.82065272382200311435413206848451310067,
+        0.822877739076982422259378362362911222833,
+        0.825108786960308875483586738272485101678,
+        0.827345883828097198786118571797909120834,
+        0.829589046080808042697824787210781231927,
+        0.831838290163368217523168228488195222638,
+        0.834093632565291253329796170708536192903,
+        0.836355089820798286809404612069230711295,
+        0.83862267850893927589613232455870870518,
+        0.84089641525371454303112547623321489504,
+        0.84317631672419664796432298771385230143,
+        0.84546239963465259098692866759361830709,
+        0.84775468074466634749045860363936420312,
+        0.850053176859261734750681286748751167545,
+        0.852357904829025611837203530384718316326,
+        0.854668881550231413551897437515331498025,
+        0.856986123964963019301812477839166009452,
+        0.859309649061238957814672188228156252257,
+        0.861639473873136948607517116872358729753,
+        0.863975615480918781121524414614366207052,
+        0.866318091011155532438509953514163469652,
+        0.868666917636853124497101040936083380124,
+        0.871022112577578221729056715595464682243,
+        0.873383693099584470038708278290226842228,
+        0.875751676515939078050995142767930296012,
+        0.878126080186649741556080309687656610647,
+        0.880506921518791912081045787323636256171,
+        0.882894217966636410521691124969260937028,
+        0.885287987031777386769987907431242017412,
+        0.88768824626326062627527960009966160388,
+        0.89009501325771220447985955243623523504,
+        0.892508305659467490072110281986409916153,
+        0.8949281411607004980029443898876582985,
+        0.897354537501553593213851621063890907178,
+        0.899787512470267546027427696662514569756,
+        0.902227083903311940153838631655504844215,
+        0.904673269685515934269259325789226871994,
+        0.907126087750199378124917300181170171233,
+        0.909585556079304284147971563828178746372,
+        0.91205169270352665549806275316460097744,
+        0.914524515702448671545983912696158354092,
+        0.91700404320467123174354159479414442804,
+        0.919490293387946858856304371174663918816,
+        0.921983284479312962533570386670938449637,
+        0.92448303475522546419252726694739603678,
+        0.92698956254169278419622653516884831976,
+        0.929502886214410192307650717745572682403,
+        0.932023024198894522404814545597236289343,
+        0.934549994970619252444512104439799143264,
+        0.93708381705514995066499947497722326722,
+        0.93962450902828008902058735120448448827,
+        0.942172089516167224843810351983745154882,
+        0.944726577195469551733539267378681531548,
+        0.947287990793482820670109326713462307376,
+        0.949856349088277632361251759806996099924,
+        0.952431670908837101825337466217860725517,
+        0.955013975135194896221170529572799135168,
+        0.957603280698573646936305635147915443924,
+        0.960199606581523736948607188887070611744,
+        0.962802971818062464478519115091191368377,
+        0.965413395493813583952272948264534783197,
+        0.968030896746147225299027952283345762418,
+        0.970655494764320192607710617437589705184,
+        0.973287208789616643172102023321302921373,
+        0.97592605811548914795551023340047499377,
+        0.978572062087700134509161125813435745597,
+        0.981225240104463713381244885057070325016,
+        0.983885611616587889056366801238014683926,
+        0.98655319612761715646797006813220671315,
+        0.989228013193975484129124959065583667775,
+        0.99191008242510968492991311132615581644,
+        0.994599423483633175652477686222166314457,
+        0.997296056085470126257659913847922601123,
+        1.0,
+        1.00271127505020248543074558845036204047,
+        1.0054299011128028213513839559347998147,
+        1.008155898118417515783094890817201039276,
+        1.01088928605170046002040979056186052439,
+        1.013630084951489438840258929063939929597,
+        1.01637831491095303794049311378629406276,
+        1.0191339960777379496848780958207928794,
+        1.02189714865411667823448013478329943978,
+        1.02466779289713564514828907627081492763,
+        1.0274459491187636965388611939222137815,
+        1.030231637686041012871707902453904567093,
+        1.033024879021228422500108283970460918086,
+        1.035825693601957120029983209018081371844,
+        1.03863410196137879061243669795463973258,
+        1.04145012468831614126454607901189312648,
+        1.044273782427413840321966478739929008784,
+        1.04710509587928986612990725022711224056,
+        1.04994408580068726608203812651590790906,
+        1.05279077300462632711989120298074630319,
+        1.05564517836055715880834132515293865216,
+        1.058507322794512690105772109683716645074,
+        1.061377227289262080950567678003883726294,
+        1.06425491288446454978861125700158022068,
+        1.06714040067682361816952112099280916261,
+        1.0700337118202417735424119367576235685,
+        1.072934867525975551385035450873827585343,
+        1.075843889062791037803228648476057074063,
+        1.07876079775711979374068003743848295849,
+        1.081685614993215201942115594422531125643,
+        1.08461836221330923781610517190661434161,
+        1.087559060917769665346797830944039707867,
+        1.09050773266525765920701065576070797899,
+        1.09346439907288585422822014625044716208,
+        1.096429081816376823386138295859248481766,
+        1.09940180263022198546369696823882990404,
+        1.10238258330784094355641420942564685751,
+        1.10537144570174125558827469625695031104,
+        1.108368411723678638009423649426619850137,
+        1.111373503344817603850149254228916637444,
+        1.1143867425958925363088129569196030678,
+        1.11740815156736919905457996308578026665,
+        1.12043775240960668442900387986631301277,
+        1.123475567333019800733729739775321431954,
+        1.12652161860824189979479864378703477763,
+        1.129575928566288145997264988840249825907,
+        1.13263851959871922798707372367762308438,
+        1.13570941415780551424039033067611701343,
+        1.13878863475669165370383028384151125472,
+        1.14187620396956162271229760828788093894,
+        1.14497214443180421939441388822291589579,
+        1.14807647884017900677879966269734268003,
+        1.15118922995298270581775963520198253612,
+        1.154310420590216039548221528724806960684,
+        1.157440073633751029613085766293796821106,
+        1.16057821202749874636945947257609098625,
+        1.16372485877757751381357359909218531234,
+        1.166880036952481570555516298414089287834,
+        1.170043769683250188080259035792738573,
+        1.17321608016363724753480435451324538889,
+        1.176396991650281276284645728483848641054,
+        1.17958652746287594548610056676944051898,
+        1.182784710984341029924457204693850757966,
+        1.18599156566099383137126564953421556374,
+        1.18920711500272106671749997056047591529,
+        1.19243138258315122214272755814543101148,
+        1.195664392039827374583837049865451975705,
+        1.19890616707438048177030255797630020695,
+        1.202156731452703142096396957497765876003,
+        1.205416109005123825604211432558411335666,
+        1.208684323626581577354792255889216998484,
+        1.21196139927680119446816891773249304545,
+        1.215247359980468878116520251338798457624,
+        1.218542229827408361758207148117394510724,
+        1.221846032972757516903891841911570785836,
+        1.225158793637145437709464594384845353707,
+        1.22848053610687000569400895779278184036,
+        1.2318112847340759358845566532127948166,
+        1.235151063936933305692912507415415760294,
+        1.238499898199816567833368865859612431545,
+        1.24185781207348404859367746872659560551,
+        1.24522483017525793277520496748615267417,
+        1.24860097718920473662176609730249554519,
+        1.25198627786631627006020603178920359732,
+        1.255380757024691089579390657442301194595,
+        1.25878443954971644307786044181516261876,
+        1.26219735039425070801401025851841645967,
+        1.265619514578806324196273999873453036296,
+        1.26905095719173322255441908103233800472,
+        1.27249170338940275123669204418460217677,
+        1.27594177839639210038120243475928938891,
+        1.27940120750566922691358797002785254596,
+        1.28287001607877828072666978102151405111,
+        1.286348229546025533601482208069738348355,
+        1.28983587340666581223274729549155218968,
+        1.293332973229089436725559789048704304684,
+        1.296839554651009665933754117792451159835,
+        1.30035564337965065101414056707091779129,
+        1.30388126519193589857452364895199736833,
+        1.30741644593467724479715157747196172848,
+        1.310961211524764341922991786330755849366,
+        1.314515587949354658485983613383997794965,
+        1.318079601266063994690185647066116617664,
+        1.32165327760315751432651181233060922616,
+        1.32523664315974129462953709549872167411,
+        1.32882972420595439547865089632866510792,
+        1.33243254708316144935164337949073577407,
+        1.33604513820414577344262790437186975929,
+        1.33966752405330300536003066972435257602,
+        1.34329973118683526382421714618163087542,
+        1.346941786232945835788173713229537282075,
+        1.35059371589203439140852219606013396004,
+        1.35425554693689272829801474014070280434,
+        1.357927306212901046494536695671766697446,
+        1.36160902063822475558553593883194147464,
+        1.36530071720401181543069836033754285543,
+        1.36900242297459061192960113298219283217,
+        1.37271416508766836928499785714471721579,
+        1.37643597075453010021632280551868696026,
+        1.380167867260238095581945274358283464697,
+        1.383909881963831954872659527265192818,
+        1.387662042298529159042861017950775988896,
+        1.39142437577192618714983552956624344668,
+        1.395196909966200178275574599249220994716,
+        1.398979672538311140209528136715194969206,
+        1.40277269122020470637471352433337881711,
+        1.40657599381901544248361973255451684411,
+        1.410389608217270704414375128268675481145,
+        1.41421356237309504880168872420969807857
+      };
+
+    return ldexp (exp_table[128 + m] * exp_y, n);
+  }
+}
--- a/lib/math.in.h
+++ b/lib/math.in.h
@@ -532,6 +532,30 @@
 #endif
 
 
+#if @GNULIB_EXP2@
+# if @REPLACE_EXP2@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef exp2
+#   define exp2 rpl_exp2
+#  endif
+_GL_FUNCDECL_RPL (exp2, double, (double x));
+_GL_CXXALIAS_RPL (exp2, double, (double x));
+# else
+#  if !@HAVE_DECL_EXP2@
+_GL_FUNCDECL_SYS (exp2, double, (double x));
+#  endif
+_GL_CXXALIAS_SYS (exp2, double, (double x));
+# endif
+_GL_CXXALIASWARN (exp2);
+#elif defined GNULIB_POSIXCHECK
+# undef exp2
+# if HAVE_RAW_DECL_EXP2
+_GL_WARN_ON_USE (exp2, "exp2 is unportable - "
+                 "use gnulib module exp2 for portability");
+# endif
+#endif
+
+
 #if @GNULIB_EXPM1F@
 # if @REPLACE_EXPM1F@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
new file mode 100644
--- /dev/null
+++ b/m4/exp2.m4
@@ -0,0 +1,144 @@
+# exp2.m4 serial 1
+dnl Copyright (C) 2010-2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_EXP2],
+[
+  AC_REQUIRE([gl_MATH_H_DEFAULTS])
+
+  dnl Persuade glibc <math.h> to declare exp2().
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+
+  EXP2_LIBM=
+  AC_CACHE_CHECK([whether exp2() can be used without linking with libm],
+    [gl_cv_func_exp2_no_libm],
+    [
+      AC_LINK_IFELSE(
+        [AC_LANG_PROGRAM(
+           [[#ifndef __NO_MATH_INLINES
+             # define __NO_MATH_INLINES 1 /* for glibc */
+             #endif
+             #include <math.h>
+             extern
+             #ifdef __cplusplus
+             "C"
+             #endif
+             double exp2 (double);
+             double (*funcptr) (double) = exp2;
+             double x;]],
+           [[return funcptr (x) > 1.5
+                    || exp2 (x) > 1.5;]])],
+        [gl_cv_func_exp2_no_libm=yes],
+        [gl_cv_func_exp2_no_libm=no])
+    ])
+  if test $gl_cv_func_exp2_no_libm = no; then
+    AC_CACHE_CHECK([whether exp2() can be used with libm],
+      [gl_cv_func_exp2_in_libm],
+      [
+        save_LIBS="$LIBS"
+        LIBS="$LIBS -lm"
+        AC_LINK_IFELSE(
+          [AC_LANG_PROGRAM(
+             [[#ifndef __NO_MATH_INLINES
+               # define __NO_MATH_INLINES 1 /* for glibc */
+               #endif
+               #include <math.h>
+               extern
+               #ifdef __cplusplus
+               "C"
+               #endif
+               double exp2 (double);
+               double (*funcptr) (double) = exp2;
+               double x;]],
+             [[return funcptr (x) > 1.5
+                      || exp2 (x) > 1.5;]])],
+          [gl_cv_func_exp2_in_libm=yes],
+          [gl_cv_func_exp2_in_libm=no])
+        LIBS="$save_LIBS"
+      ])
+    if test $gl_cv_func_exp2_in_libm = yes; then
+      EXP2_LIBM=-lm
+    fi
+  fi
+  if test $gl_cv_func_exp2_no_libm = yes \
+     || test $gl_cv_func_exp2_in_libm = yes; then
+    HAVE_EXP2=1
+    dnl Also check whether it's declared.
+    dnl IRIX 6.5 has exp2() in libm but doesn't declare it in <math.h>.
+    AC_CHECK_DECL([exp2], , [HAVE_DECL_EXP2=0], [[#include <math.h>]])
+    save_LIBS="$LIBS"
+    LIBS="$LIBS $EXP2_LIBM"
+    gl_FUNC_EXP2_WORKS
+    LIBS="$save_LIBS"
+    case "$gl_cv_func_exp2_works" in
+      *yes) ;;
+      *) REPLACE_EXP2=1 ;;
+    esac
+  else
+    HAVE_EXP2=0
+    HAVE_DECL_EXP2=0
+  fi
+  if test $HAVE_EXP2 = 0 || test $REPLACE_EXP2 = 1; then
+    dnl Find libraries needed to link lib/exp2.c.
+    AC_REQUIRE([gl_FUNC_ISNAND])
+    AC_REQUIRE([gl_FUNC_ROUND])
+    AC_REQUIRE([gl_FUNC_LDEXP])
+    EXP2_LIBM=
+    dnl Append $ISNAND_LIBM to EXP2_LIBM, avoiding gratuitous duplicates.
+    case " $EXP2_LIBM " in
+      *" $ISNAND_LIBM "*) ;;
+      *) EXP2_LIBM="$EXP2_LIBM $ISNAND_LIBM" ;;
+    esac
+    dnl Append $ROUND_LIBM to EXP2_LIBM, avoiding gratuitous duplicates.
+    case " $EXP2_LIBM " in
+      *" $ROUND_LIBM "*) ;;
+      *) EXP2_LIBM="$EXP2_LIBM $ROUND_LIBM" ;;
+    esac
+    dnl Append $LDEXP_LIBM to EXP2_LIBM, avoiding gratuitous duplicates.
+    case " $EXP2_LIBM " in
+      *" $LDEXP_LIBM "*) ;;
+      *) EXP2_LIBM="$EXP2_LIBM $LDEXP_LIBM" ;;
+    esac
+  fi
+  AC_SUBST([EXP2_LIBM])
+])
+
+dnl Test whether exp2() works.
+dnl On OpenBSD 4.9, for the argument 0.6, it returns 1.517358639986284397,
+dnl which has a relative error of 0.1%.
+AC_DEFUN([gl_FUNC_EXP2_WORKS],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  AC_CACHE_CHECK([whether exp2 works], [gl_cv_func_exp2_works],
+    [
+      AC_RUN_IFELSE(
+        [AC_LANG_SOURCE([[
+#include <math.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+double exp2 (double);
+volatile double x;
+double y;
+int main ()
+{
+  x = 0.6;
+  y = exp2 (x);
+  if (y > 1.516)
+    return 1;
+  return 0;
+}
+]])],
+        [gl_cv_func_exp2_works=yes],
+        [gl_cv_func_exp2_works=no],
+        [case "$host_os" in
+           openbsd*) gl_cv_func_exp2_works="guessing no";;
+           *)        gl_cv_func_exp2_works="guessing yes";;
+         esac
+        ])
+    ])
+])
--- a/m4/math_h.m4
+++ b/m4/math_h.m4
@@ -1,4 +1,4 @@
-# math_h.m4 serial 88
+# math_h.m4 serial 89
 dnl Copyright (C) 2007-2012 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -41,7 +41,7 @@
   gl_WARN_ON_USE_PREPARE([[#include <math.h>]],
     [acosf acosl asinf asinl atanf atanl
      cbrt cbrtf cbrtl ceilf ceill copysign copysignf copysignl cosf cosl coshf
-     expf expl expm1 expm1f expm1l fabsf fabsl floorf floorl fma fmaf fmal
+     expf expl exp2 expm1 expm1f expm1l fabsf fabsl floorf floorl fma fmaf fmal
      fmod fmodf fmodl frexpf frexpl hypotf hypotl
      ldexpf ldexpl logb logf logl log10f log10l modf modff modfl powf
      remainder remainderf remainderl
@@ -81,6 +81,7 @@
   GNULIB_COSHF=0;      AC_SUBST([GNULIB_COSHF])
   GNULIB_EXPF=0;       AC_SUBST([GNULIB_EXPF])
   GNULIB_EXPL=0;       AC_SUBST([GNULIB_EXPL])
+  GNULIB_EXP2=0;       AC_SUBST([GNULIB_EXP2])
   GNULIB_EXPM1=0;      AC_SUBST([GNULIB_EXPM1])
   GNULIB_EXPM1F=0;     AC_SUBST([GNULIB_EXPM1F])
   GNULIB_EXPM1L=0;     AC_SUBST([GNULIB_EXPM1L])
@@ -202,6 +203,7 @@
   HAVE_DECL_COPYSIGNF=1;       AC_SUBST([HAVE_DECL_COPYSIGNF])
   HAVE_DECL_COSL=1;            AC_SUBST([HAVE_DECL_COSL])
   HAVE_DECL_EXPL=1;            AC_SUBST([HAVE_DECL_EXPL])
+  HAVE_DECL_EXP2=1;            AC_SUBST([HAVE_DECL_EXP2])
   HAVE_DECL_EXPM1L=1;          AC_SUBST([HAVE_DECL_EXPM1L])
   HAVE_DECL_FLOORF=1;          AC_SUBST([HAVE_DECL_FLOORF])
   HAVE_DECL_FLOORL=1;          AC_SUBST([HAVE_DECL_FLOORL])
@@ -229,6 +231,7 @@
   REPLACE_CEILL=0;             AC_SUBST([REPLACE_CEILL])
   REPLACE_EXPM1=0;             AC_SUBST([REPLACE_EXPM1])
   REPLACE_EXPM1F=0;            AC_SUBST([REPLACE_EXPM1F])
+  REPLACE_EXP2=0;              AC_SUBST([REPLACE_EXP2])
   REPLACE_FABSL=0;             AC_SUBST([REPLACE_FABSL])
   REPLACE_FLOOR=0;             AC_SUBST([REPLACE_FLOOR])
   REPLACE_FLOORF=0;            AC_SUBST([REPLACE_FLOORF])
new file mode 100644
--- /dev/null
+++ b/modules/exp2
@@ -0,0 +1,35 @@
+Description:
+exp2() function: exponential base 2 function.
+
+Files:
+lib/exp2.c
+m4/exp2.m4
+m4/mathfunc.m4
+
+Depends-on:
+math
+extensions
+isnand          [test $HAVE_EXP2 = 0 || test $REPLACE_EXP2 = 1]
+round           [test $HAVE_EXP2 = 0 || test $REPLACE_EXP2 = 1]
+ldexp           [test $HAVE_EXP2 = 0 || test $REPLACE_EXP2 = 1]
+
+configure.ac:
+gl_FUNC_EXP2
+if test $HAVE_EXP2 = 0 || test $REPLACE_EXP2 = 1; then
+  AC_LIBOBJ([exp2])
+fi
+gl_MATH_MODULE_INDICATOR([exp2])
+
+Makefile.am:
+
+Include:
+<math.h>
+
+Link:
+$(EXP2_LIBM)
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible
--- a/modules/math
+++ b/modules/math
@@ -49,6 +49,7 @@
 	      -e 's/@''GNULIB_COSHF''@/$(GNULIB_COSHF)/g' \
 	      -e 's/@''GNULIB_EXPF''@/$(GNULIB_EXPF)/g' \
 	      -e 's/@''GNULIB_EXPL''@/$(GNULIB_EXPL)/g' \
+	      -e 's/@''GNULIB_EXP2''@/$(GNULIB_EXP2)/g' \
 	      -e 's/@''GNULIB_EXPM1''@/$(GNULIB_EXPM1)/g' \
 	      -e 's/@''GNULIB_EXPM1F''@/$(GNULIB_EXPM1F)/g' \
 	      -e 's/@''GNULIB_EXPM1L''@/$(GNULIB_EXPM1L)/g' \
@@ -170,6 +171,7 @@
 	      -e 's|@''HAVE_DECL_COPYSIGNF''@|$(HAVE_DECL_COPYSIGNF)|g' \
 	      -e 's|@''HAVE_DECL_COSL''@|$(HAVE_DECL_COSL)|g' \
 	      -e 's|@''HAVE_DECL_EXPL''@|$(HAVE_DECL_EXPL)|g' \
+	      -e 's|@''HAVE_DECL_EXP2''@|$(HAVE_DECL_EXP2)|g' \
 	      -e 's|@''HAVE_DECL_EXPM1L''@|$(HAVE_DECL_EXPM1L)|g' \
 	      -e 's|@''HAVE_DECL_FLOORF''@|$(HAVE_DECL_FLOORF)|g' \
 	      -e 's|@''HAVE_DECL_FLOORL''@|$(HAVE_DECL_FLOORL)|g' \
@@ -198,6 +200,7 @@
 	      -e 's|@''REPLACE_CEILL''@|$(REPLACE_CEILL)|g' \
 	      -e 's|@''REPLACE_EXPM1''@|$(REPLACE_EXPM1)|g' \
 	      -e 's|@''REPLACE_EXPM1F''@|$(REPLACE_EXPM1F)|g' \
+	      -e 's|@''REPLACE_EXP2''@|$(REPLACE_EXP2)|g' \
 	      -e 's|@''REPLACE_FABSL''@|$(REPLACE_FABSL)|g' \
 	      -e 's|@''REPLACE_FLOOR''@|$(REPLACE_FLOOR)|g' \
 	      -e 's|@''REPLACE_FLOORF''@|$(REPLACE_FLOORF)|g' \
--- a/tests/test-math-c++.cc
+++ b/tests/test-math-c++.cc
@@ -124,6 +124,10 @@
 SIGNATURE_CHECK (GNULIB_NAMESPACE::expl, long double, (long double));
 #endif
 
+#if GNULIB_TEST_EXP2
+SIGNATURE_CHECK (GNULIB_NAMESPACE::exp2, double, (double));
+#endif
+
 #if GNULIB_TEST_EXPM1F
 SIGNATURE_CHECK (GNULIB_NAMESPACE::expm1f, float, (float));
 #endif