diff --git a/src/image/color/cie1931.cpp b/src/image/color/cie1931.cpp
index 1abecfaa..73beb0f4 100644
--- a/src/image/color/cie1931.cpp
+++ b/src/image/color/cie1931.cpp
@@ -26,6 +26,8 @@ namespace lol
 
 float Color::DistanceCIEDE2000(vec3 lab1, vec3 lab2)
 {
+    float const pi = 3.141592653589793f;
+
     float const deg2rad = 6.28318530718f / 360.f;
     float const rad2deg = 360.f / 6.28318530718f;
 
@@ -47,36 +49,36 @@ float Color::DistanceCIEDE2000(vec3 lab1, vec3 lab2)
     float dCp = Cp2 - Cp1;
     float Cp_ = 0.5f * (Cp1 + Cp2);
 
-    float hp1 = fmod(atan2(lab1.z, ap1) * rad2deg, 360.f);
-    if (hp1 < 0.f)
-        hp1 += 360.f;
-    float hp2 = fmod(atan2(lab2.z, ap2) * rad2deg, 360.f);
-    if (hp2 < 0.f)
-        hp2 += 360.f;
-    float dhp;
-    if (abs(hp1 - hp2) <= 180.f)
+    float hp1 = fmod(atan2(lab1.z, ap1) + 2.f * pi, 2.f * pi);
+    float hp2 = fmod(atan2(lab2.z, ap2) + 2.f * pi, 2.f * pi);
+    float dhp; /* -pi .. pi */
+    if (abs(hp1 - hp2) <= pi)
         dhp = hp2 - hp1;
     else if (hp2 <= hp1)
-        dhp = hp2 - hp1 + 360.f;
+        dhp = hp2 - hp1 + 2.f * pi;
     else
-        dhp = hp2 - hp1 - 360.f;
-    float dHp = 2.f * sqrt(Cp1 * Cp2) * sin(dhp / 2.f * deg2rad);
-    float Hp_;
-    if (abs(hp1 - hp2) > 180.f)
-        Hp_ = 0.5f * (hp1 + hp2 + 360.f);
+        dhp = hp2 - hp1 - 2.f * pi;
+    float dHp = 2.f * sqrt(Cp1 * Cp2) * sin(dhp / 2.f);
+    float Hp_; /* half-angle 0 .. 360 */
+    if (!(Cp1 * Cp2))
+        Hp_ = hp1 + hp2;
+    else if (abs(hp1 - hp2) > pi && hp1 + hp2 < 2.f * pi)
+        Hp_ = 0.5f * (hp1 + hp2) + pi;
+    else if (abs(hp1 - hp2) > 180.f)
+        Hp_ = 0.5f * (hp1 + hp2) - pi;
     else
         Hp_ = 0.5f * (hp1 + hp2);
 
-    float T = 1.f - 0.17f * cos((Hp_ - 30.f) * deg2rad)
-                  + 0.24f * cos(2 * Hp_ * deg2rad)
-                  + 0.32f * cos((3.f * Hp_ + 6.f) * deg2rad)
-                  - 0.20f * cos((4.f * Hp_ - 63.f) * deg2rad);
+    float T = 1.f - 0.17f * cos(Hp_ - pi / 6.f)
+                  + 0.24f * cos(2.f * Hp_)
+                  + 0.32f * cos(3.f * Hp_ + pi / 30.f)
+                  - 0.20f * cos(4.f * Hp_ - 0.35f * pi);
     float SL = 1.f + 0.015f * (L_ - 50) * (L_ - 50)
                             / sqrt(20.f + (L_ - 50) * (L_ - 50));
     float SC = 1.f + 0.045f * Cp_;
     float SH = 1.f + 0.015f * Cp_ * T;
     float RT = -2.f * sqrt(pow(Cp_, 7.f) / (pow(Cp_, 7.f) + pow(25.f, 7.f)))
-                    * sin(60.f * deg2rad * exp(-pow((Hp_ - 275.f) / 25.f, 2.f)));
+                    * sin(60.f * deg2rad * exp(-pow((Hp_ * rad2deg - 275.f) / 25.f, 2.f)));
 
     dLp /= SL;
     dCp /= SC;
diff --git a/test/Makefile.am b/test/Makefile.am
index 458d75be..7dcd6fd2 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -22,7 +22,8 @@ endif
 testsuite_SOURCES = testsuite.cpp \
     unit/vector.cpp unit/matrix.cpp unit/half.cpp unit/trig.cpp \
     unit/build.cpp unit/real.cpp unit/image.cpp unit/quat.cpp unit/cmplx.cpp \
-    unit/array.cpp unit/rotation.cpp unit/string.cpp unit/map.cpp
+    unit/array.cpp unit/rotation.cpp unit/string.cpp unit/map.cpp \
+    unit/color.cpp
 testsuite_CPPFLAGS = @LOL_CFLAGS@
 testsuite_LDFLAGS = $(top_builddir)/src/liblol.a @LOL_LIBS@
 testsuite_DEPENDENCIES = $(top_builddir)/src/liblol.a
diff --git a/test/testsuite.vcxproj b/test/testsuite.vcxproj
index dc93dd80..b00ed9fd 100644
--- a/test/testsuite.vcxproj
+++ b/test/testsuite.vcxproj
@@ -39,6 +39,7 @@
     <ClCompile Include="unit\array.cpp" />
     <ClCompile Include="unit\build.cpp" />
     <ClCompile Include="unit\cmplx.cpp" />
+    <ClCompile Include="unit\color.cpp" />
     <ClCompile Include="unit\half.cpp" />
     <ClCompile Include="unit\image.cpp" />
     <ClCompile Include="unit\map.cpp" />
diff --git a/test/unit/color.cpp b/test/unit/color.cpp
new file mode 100644
index 00000000..86c9d2e5
--- /dev/null
+++ b/test/unit/color.cpp
@@ -0,0 +1,87 @@
+//
+// Lol Engine
+//
+// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
+//   This program is free software; you can redistribute it and/or
+//   modify it under the terms of the Do What The Fuck You Want To
+//   Public License, Version 2, as published by Sam Hocevar. See
+//   http://www.wtfpl.net/ for more details.
+//
+
+#if defined HAVE_CONFIG_H
+#   include "config.h"
+#endif
+
+#include "core.h"
+#include "lol/unit.h"
+
+namespace lol
+{
+
+/* Data taken from “The CIEDE2000 Color-Difference Formula: Implementation
+ * Notes, Supplementary Test Data, and Mathematical Observations” (2004)
+ * by Gaurav Sharma, Wencheng Wu, Edul N. Dalal. Some data is disabled
+ * because it is at the discontinuity limit. */
+static float const ciede2k[] =
+{
+    50.0000f,   2.6772f, -79.7751f, 50.0000f,   0.0000f, -82.7485f,  2.0425f,
+    50.0000f,   3.1571f, -77.2803f, 50.0000f,   0.0000f, -82.7485f,  2.8615f,
+    50.0000f,   2.8361f, -74.0200f, 50.0000f,   0.0000f, -82.7485f,  3.4412f,
+    50.0000f,  -1.3802f, -84.2814f, 50.0000f,   0.0000f, -82.7485f,  1.0000f,
+    50.0000f,  -1.1848f, -84.8006f, 50.0000f,   0.0000f, -82.7485f,  1.0000f,
+    50.0000f,  -0.9009f, -85.5211f, 50.0000f,   0.0000f, -82.7485f,  1.0000f,
+    50.0000f,   0.0000f,   0.0000f, 50.0000f,  -1.0000f,   2.0000f,  2.3669f,
+    50.0000f,  -1.0000f,   2.0000f, 50.0000f,   0.0000f,   0.0000f,  2.3669f,
+    50.0000f,   2.4900f,  -0.0010f, 50.0000f,  -2.4900f,   0.0009f,  7.1792f,
+    50.0000f,   2.4900f,  -0.0010f, 50.0000f,  -2.4900f,   0.0010f,  7.1792f,
+    //50.0000f,   2.4900f,  -0.0010f, 50.0000f,  -2.4900f,   0.0011f,  7.2195f,
+    //50.0000f,   2.4900f,  -0.0010f, 50.0000f,  -2.4900f,   0.0012f,  7.2195f,
+    50.0000f,  -0.0010f,   2.4900f, 50.0000f,   0.0009f,  -2.4900f,  4.8045f,
+    50.0000f,  -0.0010f,   2.4900f, 50.0000f,   0.0010f,  -2.4900f,  4.8045f,
+    //50.0000f,  -0.0010f,   2.4900f, 50.0000f,   0.0011f,  -2.4900f,  4.7461f,
+    50.0000f,   2.5000f,   0.0000f, 50.0000f,   0.0000f,  -2.5000f,  4.3065f,
+    50.0000f,   2.5000f,   0.0000f, 73.0000f,  25.0000f, -18.0000f, 27.1492f,
+    50.0000f,   2.5000f,   0.0000f, 61.0000f,  -5.0000f,  29.0000f, 22.8977f,
+    50.0000f,   2.5000f,   0.0000f, 56.0000f, -27.0000f,  -3.0000f, 31.9030f,
+    50.0000f,   2.5000f,   0.0000f, 58.0000f,  24.0000f,  15.0000f, 19.4535f,
+    50.0000f,   2.5000f,   0.0000f, 50.0000f,   3.1736f,   0.5854f,  1.0000f,
+    50.0000f,   2.5000f,   0.0000f, 50.0000f,   3.2972f,   0.0000f,  1.0000f,
+    50.0000f,   2.5000f,   0.0000f, 50.0000f,   1.8634f,   0.5757f,  1.0000f,
+    50.0000f,   2.5000f,   0.0000f, 50.0000f,   3.2592f,   0.3350f,  1.0000f,
+    60.2574f, -34.0099f,  36.2677f, 60.4626f, -34.1751f,  39.4387f,  1.2644f,
+    63.0109f, -31.0961f,  -5.8663f, 62.8187f, -29.7946f,  -4.0864f,  1.2630f,
+    61.2901f,   3.7196f,  -5.3901f, 61.4292f,   2.2480f,  -4.9620f,  1.8731f,
+    35.0831f, -44.1164f,   3.7933f, 35.0232f, -40.0716f,   1.5901f,  1.8645f,
+    22.7233f,  20.0904f, -46.6940f, 23.0331f,  14.9730f, -42.5619f,  2.0373f,
+    36.4612f,  47.8580f,  18.3852f, 36.2715f,  50.5065f,  21.2231f,  1.4146f,
+    90.8027f,  -2.0831f,   1.4410f, 91.1528f,  -1.6435f,   0.0447f,  1.4441f,
+    90.9257f,  -0.5406f,  -0.9208f, 88.6381f,  -0.8985f,  -0.7239f,  1.5381f,
+     6.7747f,  -0.2908f,  -2.4247f,  5.8714f,  -0.0985f,  -2.2286f,  0.6377f,
+     2.0776f,   0.0795f,  -1.1350f,  0.9033f,  -0.0636f,  -0.5514f,  0.9082f,
+};
+
+LOLUNIT_FIXTURE(ColorTest)
+{
+    void SetUp() {}
+
+    void TearDown() {}
+
+    LOLUNIT_TEST(CIEDE2000)
+    {
+        size_t count = sizeof(ciede2k) / sizeof(*ciede2k);
+
+        for (size_t n = 0; n < count; n += 7)
+        {
+            vec3 a(ciede2k[n + 0], ciede2k[n + 1], ciede2k[n + 2]);
+            vec3 b(ciede2k[n + 3], ciede2k[n + 4], ciede2k[n + 5]);
+            float d1 = ciede2k[n + 6];
+
+            float d2 = Color::DistanceCIEDE2000(a, b);
+
+            LOLUNIT_ASSERT_DOUBLES_EQUAL(d1, d2, 0.0001);
+        }
+    }
+};
+
+} /* namespace lol */
+