diff --git a/src/ReplayGainGlobal.cxx b/src/ReplayGainGlobal.cxx
index 98b8dcda0..af82c2288 100644
--- a/src/ReplayGainGlobal.cxx
+++ b/src/ReplayGainGlobal.cxx
@@ -20,12 +20,12 @@
 #include "ReplayGainGlobal.hxx"
 #include "ReplayGainConfig.hxx"
 #include "config/Data.hxx"
+#include "util/Math.hxx"
 
 #include <cassert>
 #include <stdexcept>
 
 #include <stdlib.h>
-#include <math.h>
 
 static float
 ParsePreamp(const char *s)
diff --git a/src/ReplayGainInfo.cxx b/src/ReplayGainInfo.cxx
index a0685507a..76713aded 100644
--- a/src/ReplayGainInfo.cxx
+++ b/src/ReplayGainInfo.cxx
@@ -19,8 +19,7 @@
 
 #include "ReplayGainInfo.hxx"
 #include "ReplayGainConfig.hxx"
-
-#include <math.h>
+#include "util/Math.hxx"
 
 float
 ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const noexcept
diff --git a/src/Stats.cxx b/src/Stats.cxx
index 2208312d7..7467a3a17 100644
--- a/src/Stats.cxx
+++ b/src/Stats.cxx
@@ -28,13 +28,13 @@
 #include "db/Stats.hxx"
 #include "Log.hxx"
 #include "time/ChronoUtil.hxx"
+#include "util/Math.hxx"
 
 #ifdef _WIN32
 #include "system/Clock.hxx"
 #endif
 
 #include <chrono>
-#include <cmath>
 
 #ifndef _WIN32
 /**
@@ -126,7 +126,7 @@ stats_print(Response &r, const Partition &partition)
 	r.Format("uptime: %u\n"
 		 "playtime: %lu\n",
 		 (unsigned)std::chrono::duration_cast<std::chrono::seconds>(uptime).count(),
-		 std::lround(partition.pc.GetTotalPlayTime().count()));
+		 lround(partition.pc.GetTotalPlayTime().count()));
 
 #ifdef ENABLE_DATABASE
 	const Database *db = partition.instance.GetDatabase();
diff --git a/src/command/PlayerCommands.cxx b/src/command/PlayerCommands.cxx
index 551a67905..ecd2156e5 100644
--- a/src/command/PlayerCommands.cxx
+++ b/src/command/PlayerCommands.cxx
@@ -32,13 +32,12 @@
 #include "util/StringBuffer.hxx"
 #include "util/ScopeExit.hxx"
 #include "util/Exception.hxx"
+#include "util/Math.hxx"
 
 #ifdef ENABLE_DATABASE
 #include "db/update/Service.hxx"
 #endif
 
-#include <cmath>
-
 #define COMMAND_STATUS_STATE            "state"
 #define COMMAND_STATUS_REPEAT           "repeat"
 #define COMMAND_STATUS_SINGLE           "single"
@@ -155,7 +154,7 @@ handle_status(Client &client, [[maybe_unused]] Request args, Response &r)
 
 	if (pc.GetCrossFade() > FloatDuration::zero())
 		r.Format(COMMAND_STATUS_CROSSFADE ": %lu\n",
-			 std::lround(pc.GetCrossFade().count()));
+			 lround(pc.GetCrossFade().count()));
 
 	if (pc.GetMixRampDelay() > FloatDuration::zero())
 		r.Format(COMMAND_STATUS_MIXRAMPDELAY ": %f\n",
diff --git a/src/decoder/Bridge.cxx b/src/decoder/Bridge.cxx
index b87466798..b7f71c1b8 100644
--- a/src/decoder/Bridge.cxx
+++ b/src/decoder/Bridge.cxx
@@ -37,9 +37,9 @@
 #include "util/StringBuffer.hxx"
 
 #include <cassert>
+#include <cmath>
 
 #include <string.h>
-#include <math.h>
 
 DecoderBridge::DecoderBridge(DecoderControl &_dc, bool _initial_seek_pending,
 			     std::unique_ptr<Tag> _tag) noexcept
@@ -611,7 +611,7 @@ DecoderBridge::SubmitReplayGain(const ReplayGainInfo *new_replay_gain_info) noex
 			const auto &tuple = new_replay_gain_info->Get(rgm);
 			const auto scale =
 				tuple.CalculateScale(dc.replay_gain_config);
-			dc.replay_gain_db = 20.0 * log10f(scale);
+			dc.replay_gain_db = 20.0 * std::log10(scale);
 		}
 
 		replay_gain_info = *new_replay_gain_info;
diff --git a/src/decoder/plugins/FaadDecoderPlugin.cxx b/src/decoder/plugins/FaadDecoderPlugin.cxx
index 5875a743a..40072f953 100644
--- a/src/decoder/plugins/FaadDecoderPlugin.cxx
+++ b/src/decoder/plugins/FaadDecoderPlugin.cxx
@@ -26,12 +26,12 @@
 #include "util/ScopeExit.hxx"
 #include "util/ConstBuffer.hxx"
 #include "util/Domain.hxx"
+#include "util/Math.hxx"
 #include "Log.hxx"
 
 #include <neaacdec.h>
 
 #include <cassert>
-#include <cmath>
 
 #include <string.h>
 
diff --git a/src/decoder/plugins/MpcdecDecoderPlugin.cxx b/src/decoder/plugins/MpcdecDecoderPlugin.cxx
index c19aee75c..4e9ef798e 100644
--- a/src/decoder/plugins/MpcdecDecoderPlugin.cxx
+++ b/src/decoder/plugins/MpcdecDecoderPlugin.cxx
@@ -25,6 +25,7 @@
 #include "tag/Handler.hxx"
 #include "util/Domain.hxx"
 #include "util/Clamp.hxx"
+#include "util/Math.hxx"
 #include "util/ScopeExit.hxx"
 #include "Log.hxx"
 
@@ -32,8 +33,6 @@
 
 #include <iterator>
 
-#include <math.h>
-
 struct mpc_decoder_data {
 	InputStream &is;
 	DecoderClient *client;
diff --git a/src/decoder/plugins/WavpackDecoderPlugin.cxx b/src/decoder/plugins/WavpackDecoderPlugin.cxx
index 4bb629d25..f1836ba3d 100644
--- a/src/decoder/plugins/WavpackDecoderPlugin.cxx
+++ b/src/decoder/plugins/WavpackDecoderPlugin.cxx
@@ -25,6 +25,7 @@
 #include "tag/Handler.hxx"
 #include "fs/Path.hxx"
 #include "util/Alloc.hxx"
+#include "util/Math.hxx"
 #include "util/ScopeExit.hxx"
 #include "util/RuntimeError.hxx"
 
@@ -263,8 +264,7 @@ wavpack_decode(DecoderClient &client, WavpackContext *wpc, bool can_seek)
 		if (samples_got == 0)
 			break;
 
-		int bitrate = (int)(WavpackGetInstantBitrate(wpc) / 1000 +
-				    0.5);
+		int bitrate = lround(WavpackGetInstantBitrate(wpc) / 1000);
 		format_samples(chunk, samples_got * audio_format.channels);
 
 		cmd = client.SubmitData(nullptr, chunk,
diff --git a/src/mixer/plugins/AlsaMixerPlugin.cxx b/src/mixer/plugins/AlsaMixerPlugin.cxx
index 836989cee..0016a4598 100644
--- a/src/mixer/plugins/AlsaMixerPlugin.cxx
+++ b/src/mixer/plugins/AlsaMixerPlugin.cxx
@@ -26,6 +26,7 @@
 #include "event/Call.hxx"
 #include "util/ASCII.hxx"
 #include "util/Domain.hxx"
+#include "util/Math.hxx"
 #include "util/RuntimeError.hxx"
 #include "Log.hxx"
 
@@ -35,8 +36,6 @@ extern "C" {
 
 #include <alsa/asoundlib.h>
 
-#include <math.h>
-
 #define VOLUME_MIXER_ALSA_DEFAULT		"default"
 #define VOLUME_MIXER_ALSA_CONTROL_DEFAULT	"PCM"
 static constexpr unsigned VOLUME_MIXER_ALSA_INDEX_DEFAULT = 0;
diff --git a/src/mixer/plugins/SoftwareMixerPlugin.cxx b/src/mixer/plugins/SoftwareMixerPlugin.cxx
index 0a84fa36d..f2801cf03 100644
--- a/src/mixer/plugins/SoftwareMixerPlugin.cxx
+++ b/src/mixer/plugins/SoftwareMixerPlugin.cxx
@@ -23,8 +23,9 @@
 #include "pcm/Volume.hxx"
 
 #include <cassert>
+#include <cmath>
 
-#include <math.h>
+#include <assert.h>
 
 class SoftwareMixer final : public Mixer {
 	Filter *filter = nullptr;
@@ -74,7 +75,7 @@ PercentVolumeToSoftwareVolume(unsigned volume) noexcept
 	if (volume >= 100)
 		return PCM_VOLUME_1;
 	else if (volume > 0)
-		return pcm_float_to_volume((exp(volume / 25.0) - 1) /
+		return pcm_float_to_volume((std::exp(volume / 25.0) - 1) /
 					   (54.5981500331F - 1));
 	else
 		return 0;
diff --git a/src/mixer/plugins/WinmmMixerPlugin.cxx b/src/mixer/plugins/WinmmMixerPlugin.cxx
index 49165b6cb..3bf15a8b0 100644
--- a/src/mixer/plugins/WinmmMixerPlugin.cxx
+++ b/src/mixer/plugins/WinmmMixerPlugin.cxx
@@ -20,13 +20,13 @@
 #include "mixer/MixerInternal.hxx"
 #include "output/OutputAPI.hxx"
 #include "output/plugins/WinmmOutputPlugin.hxx"
+#include "util/Math.hxx"
 
 #include <mmsystem.h>
 
 #include <cassert>
 #include <stdexcept>
 
-#include <math.h>
 #include <windows.h>
 
 class WinmmMixer final : public Mixer {
diff --git a/src/mixer/plugins/volume_mapping.c b/src/mixer/plugins/volume_mapping.c
index 61a7138af..beecce640 100644
--- a/src/mixer/plugins/volume_mapping.c
+++ b/src/mixer/plugins/volume_mapping.c
@@ -34,11 +34,6 @@
 #include <stdbool.h>
 #include "volume_mapping.h"
 
-#ifdef __UCLIBC__
-/* 10^x = 10^(log e^x) = (e^x)^log10 = e^(x * log 10) */
-#define exp10(x) (exp((x) * log(10)))
-#endif /* __UCLIBC__ */
-
 #define MAX_LINEAR_DB_SCALE	24
 
 static inline bool use_linear_dB_scale(long dBmin, long dBmax)
@@ -111,9 +106,9 @@ static double get_normalized_volume(snd_mixer_elem_t *elem,
 	if (use_linear_dB_scale(min, max))
 		return (value - min) / (double)(max - min);
 
-	normalized = exp10((value - max) / 6000.0);
+	normalized = pow(10, (value - max) / 6000.0);
 	if (min != SND_CTL_TLV_DB_GAIN_MUTE) {
-		min_norm = exp10((min - max) / 6000.0);
+		min_norm = pow(10, (min - max) / 6000.0);
 		normalized = (normalized - min_norm) / (1 - min_norm);
 	}
 
@@ -159,7 +154,7 @@ static int set_normalized_volume(snd_mixer_elem_t *elem,
 	}
 
 	if (min != SND_CTL_TLV_DB_GAIN_MUTE) {
-		min_norm = exp10((min - max) / 6000.0);
+		min_norm = pow(10, (min - max) / 6000.0);
 		volume = volume * (1 - min_norm) + min_norm;
 	}
 	value = lrint_dir(6000.0 * log10(volume), dir) + max;
diff --git a/src/output/plugins/HaikuOutputPlugin.cxx b/src/output/plugins/HaikuOutputPlugin.cxx
index e00df46eb..787a99c0d 100644
--- a/src/output/plugins/HaikuOutputPlugin.cxx
+++ b/src/output/plugins/HaikuOutputPlugin.cxx
@@ -22,6 +22,7 @@
 #include "../OutputAPI.hxx"
 #include "mixer/MixerList.hxx"
 #include "util/Domain.hxx"
+#include "util/Math.hxx"
 #include "system/Error.hxx"
 #include "Log.hxx"
 
@@ -37,8 +38,6 @@
 #include <StringList.h>
 #include <SoundPlayer.h>
 
-#include <cmath>
-
 #include <string.h>
 
 #define UTF8_PLAY "\xE2\x96\xB6"
diff --git a/src/pcm/Mix.cxx b/src/pcm/Mix.cxx
index b17343513..a39a85947 100644
--- a/src/pcm/Mix.cxx
+++ b/src/pcm/Mix.cxx
@@ -22,11 +22,11 @@
 #include "Clamp.hxx"
 #include "Traits.hxx"
 #include "util/Clamp.hxx"
+#include "util/Math.hxx"
 
 #include "Dither.cxx" // including the .cxx file to get inlined templates
 
 #include <cassert>
-#include <cmath>
 
 template<SampleFormat F, class Traits=SampleTraits<F>>
 static typename Traits::value_type
@@ -224,7 +224,7 @@ pcm_mix(PcmDither &dither, void *buffer1, const void *buffer2, size_t size,
 	s = sin(M_PI_2 * portion1);
 	s *= s;
 
-	int vol1 = std::lround(s * PCM_VOLUME_1S);
+	int vol1 = lround(s * PCM_VOLUME_1S);
 	vol1 = Clamp<int>(vol1, 0, PCM_VOLUME_1S);
 
 	return pcm_add_vol(dither, buffer1, buffer2, size,
diff --git a/src/player/CrossFade.cxx b/src/player/CrossFade.cxx
index ec8fd334e..e5611f97c 100644
--- a/src/player/CrossFade.cxx
+++ b/src/player/CrossFade.cxx
@@ -23,10 +23,10 @@
 #include "pcm/AudioFormat.hxx"
 #include "util/NumberParser.hxx"
 #include "util/Domain.hxx"
+#include "util/Math.hxx"
 #include "Log.hxx"
 
 #include <cassert>
-#include <cmath>
 
 static constexpr Domain cross_fade_domain("cross_fade");
 
@@ -111,7 +111,7 @@ CrossFadeSettings::Calculate(SignedSongTime total_time,
 
 	if (mixramp_delay <= FloatDuration::zero() ||
 	    !mixramp_start || !mixramp_prev_end) {
-		chunks = std::lround(duration / chunk_duration);
+		chunks = lround(duration / chunk_duration);
 	} else {
 		/* Calculate mixramp overlap. */
 		const auto mixramp_overlap_current =
diff --git a/src/util/Math.hxx b/src/util/Math.hxx
new file mode 100644
index 000000000..2206b045f
--- /dev/null
+++ b/src/util/Math.hxx
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 Max Kellermann <max.kellermann@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MATH_HXX
+#define MATH_HXX
+
+#ifdef __UCLIBC__
+#include <boost/math/special_functions/pow.hpp>
+#include <boost/math/special_functions/round.hpp>
+using boost::math::iround;
+using boost::math::pow;
+using boost::math::lround;
+#define lrint iround
+#else
+#include <cmath>
+using std::pow;
+using std::lrint;
+using std::lround;
+#endif
+
+#endif