extract GaussNewton.c

Use it to fit skcms_TF15, Ax^5 + Bx^4 + Cx^3 + Dx^2 + (1-A-B-C-D)x.

Change-Id: I069dbffaa589d7207d82b805e342605d1fed69fb
Reviewed-on: https://skia-review.googlesource.com/119009
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
diff --git a/build/targets b/build/targets
index 0de391e..3e87b8f 100644
--- a/build/targets
+++ b/build/targets
@@ -29,8 +29,10 @@
                                                 $out/fuzz/fuzz_main.o $
                                                 $out/skcms.o
 
+build $out/src/GaussNewton.o:      compile src/GaussNewton.c
 build $out/src/ICCProfile.o:       compile src/ICCProfile.c
 build $out/src/LinearAlgebra.o:    compile src/LinearAlgebra.c
 build $out/src/PortableMath.o:     compile src/PortableMath.c
+build $out/src/TF15.o:             compile src/TF15.c
 build $out/src/TransferFunction.o: compile src/TransferFunction.c
 build $out/src/Transform.o:        compile src/Transform.c
diff --git a/profiles/color.org/Upper_Left.icc.txt b/profiles/color.org/Upper_Left.icc.txt
index ce6fc4d..8af1604 100644
--- a/profiles/color.org/Upper_Left.icc.txt
+++ b/profiles/color.org/Upper_Left.icc.txt
@@ -20,8 +20,11 @@
  A2B : "M", Matrix, "B"
  "M" : 3 inputs
   M0 : 16-bit table with 256 entries
+  ~= : -1.802166x^5 + 3.002954x^4 + 1.592274x^3 + -3.331280x^2 + 1.538218x (Max error: 0.005243)
   M1 : 16-bit table with 256 entries
+  ~= : -1.802166x^5 + 3.002954x^4 + 1.592274x^3 + -3.331280x^2 + 1.538218x (Max error: 0.005243)
   M2 : 16-bit table with 256 entries
+  ~= : -1.802166x^5 + 3.002954x^4 + 1.592274x^3 + -3.331280x^2 + 1.538218x (Max error: 0.005243)
 Mtrx : | 0.959396958 0.847338140 0.314814538 -0.503105104 |
        | 0.489433438 1.577521086 0.133390293 -0.521812081 |
        | 0.030578148 0.213589266 1.570868373 -0.430443883 |
diff --git a/profiles/color.org/Upper_Right.icc.txt b/profiles/color.org/Upper_Right.icc.txt
index 9dafb8a..189c20d 100644
--- a/profiles/color.org/Upper_Right.icc.txt
+++ b/profiles/color.org/Upper_Right.icc.txt
@@ -22,8 +22,11 @@
 CLUT : 2 x 2 x 2 (16 bpp)
  "M" : 3 inputs
   M0 : 16-bit table with 256 entries
+  ~= : -0.163074x^5 + -1.271752x^4 + 5.104288x^3 + -3.907048x^2 + 1.237586x (Max error: 0.005173)
   M1 : 16-bit table with 256 entries
+  ~= : -0.163074x^5 + -1.271752x^4 + 5.104288x^3 + -3.907048x^2 + 1.237586x (Max error: 0.005173)
   M2 : 16-bit table with 256 entries
+  ~= : -0.163074x^5 + -1.271752x^4 + 5.104288x^3 + -3.907048x^2 + 1.237586x (Max error: 0.005173)
 Mtrx : | 2.202053785 1.944855571 0.722553670 -0.733356714 |
        | 1.123395920 3.620794296 0.306147665 -0.760608494 |
        | 0.070189357 0.490257412 3.605535746 -0.627431810 |
diff --git a/profiles/color.org/sRGB2014.icc.txt b/profiles/color.org/sRGB2014.icc.txt
index e14ab66..7a1d7d1 100644
--- a/profiles/color.org/sRGB2014.icc.txt
+++ b/profiles/color.org/sRGB2014.icc.txt
@@ -24,10 +24,13 @@
 
 rTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 gTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 bTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
  XYZ : | 0.436065674 0.385147095 0.143066406 |
        | 0.222488403 0.716873169 0.060607910 |
        | 0.013916016 0.097076416 0.714096069 |
diff --git a/profiles/misc/Apple_Color_LCD.icc.txt b/profiles/misc/Apple_Color_LCD.icc.txt
index 0da63a4..b619572 100644
--- a/profiles/misc/Apple_Color_LCD.icc.txt
+++ b/profiles/misc/Apple_Color_LCD.icc.txt
@@ -25,10 +25,13 @@
 
 rTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120847x^5 + -0.414107x^4 + 0.791163x^3 + 0.455536x^2 + 0.046562x (Max error: 0.00185)
 gTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120847x^5 + -0.414107x^4 + 0.791163x^3 + 0.455536x^2 + 0.046562x (Max error: 0.00185)
 bTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120847x^5 + -0.414107x^4 + 0.791163x^3 + 0.455536x^2 + 0.046562x (Max error: 0.00185)
  XYZ : | 0.444335938 0.379440308 0.140411377 |
        | 0.224761963 0.726165771 0.049072266 |
        | 0.005477905 0.077972412 0.741455078 |
diff --git a/profiles/misc/Coated_FOGRA39_CMYK.icc.txt b/profiles/misc/Coated_FOGRA39_CMYK.icc.txt
index b9360a9..2f2e332 100644
--- a/profiles/misc/Coated_FOGRA39_CMYK.icc.txt
+++ b/profiles/misc/Coated_FOGRA39_CMYK.icc.txt
@@ -24,11 +24,15 @@
  "A" : 4 inputs
   A0 : 16-bit table with 256 entries
   ~= : 0.968403, 1.06641, 0.0476338, 0.935616, 0.294118, -0.0979506, 0  (Max error: 0.012) (D-gap: -3.7e-05)
+  ~= : 0.223733x^5 + -0.984308x^4 + 1.057500x^3 + -0.235733x^2 + 0.938808x (Max error: 0.002631)
   A1 : 16-bit table with 256 entries
   ~= : 1.08106, 1.04424, -0.00819014, 0.766537, 0.00784314, 0.0741637, 0  (Max error: 0.11) (D-gap: 0.068)
+  ~= : -0.364609x^5 + 0.198247x^4 + 0.249158x^3 + 0.072864x^2 + 0.844341x (Max error: 0.003508)
   A2 : 16-bit table with 256 entries
   ~= : 1.15888, 1.00891, 0.0094616, 0.708171, 0.00784314, -0.00356377, 0  (Max error: 0.018) (D-gap: 7.3e-06)
+  ~= : -0.261961x^5 + 0.129644x^4 + 0.149662x^3 + 0.220228x^2 + 0.762427x (Max error: 0.003334)
   A3 : 16-bit table with 256 entries
+  ~= : -0.006767x^5 + 0.056377x^4 + 0.065259x^3 + 0.139332x^2 + 0.745799x (Max error: 0.001334)
 CLUT : 11 x 11 x 11 x 11 (16 bpp)
  "B" : 3 outputs
   B0 : 16-bit table with 2 entries
diff --git a/profiles/misc/ColorLogic_ISO_Coated_CMYK.icc.txt b/profiles/misc/ColorLogic_ISO_Coated_CMYK.icc.txt
index 172cfca..d273c33 100644
--- a/profiles/misc/ColorLogic_ISO_Coated_CMYK.icc.txt
+++ b/profiles/misc/ColorLogic_ISO_Coated_CMYK.icc.txt
@@ -23,20 +23,27 @@
  A2B : "A", CLUT, "B"
  "A" : 4 inputs
   A0 : 16-bit table with 256 entries
+  ~= : -2.430168x^5 + 6.926471x^4 + -6.735325x^3 + 2.201124x^2 + 1.037897x (Max error: 0.0113)
   A1 : 16-bit table with 256 entries
   ~= : 0.741035, 0.963444, -0.0709743, 1.24477, 0.337255, 0.0336971, 0  (Max error: 0.047) (D-gap: -0.024)
+  ~= : -2.463782x^5 + 7.004523x^4 + -6.797183x^3 + 2.220720x^2 + 1.035722x (Max error: 0.01134)
   A2 : 16-bit table with 256 entries
   ~= : 0.703794, 1.0482, -0.068751, 1.24155, 0.14902, 0.00502586, 0  (Max error: 0.017) (D-gap: -8.5e-06)
+  ~= : -2.435791x^5 + 6.948128x^4 + -6.762871x^3 + 2.215283x^2 + 1.035251x (Max error: 0.01136)
   A3 : 16-bit table with 256 entries
   ~= : 0.673778, 1.10422, 0.073473, 1.18288, 0.0156863, -0.18047, 0  (Max error: 0.064) (D-gap: -0.00044)
+  ~= : -3.545073x^5 + 11.059484x^4 + -11.098437x^3 + 3.691240x^2 + 0.892786x (Max error: 0.01577)
 CLUT : 17 x 17 x 17 x 17 (16 bpp)
  "B" : 3 outputs
   B0 : 16-bit table with 256 entries
   ~= : 1, 0.996109, 0, 0, 0, 0, 0  (Max error: 6e-08)
+  ~= : 0.256681x^5 + -0.560009x^4 + 0.419981x^3 + -0.124432x^2 + 1.007779x (Max error: 0.003891)
   B1 : 16-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 6e-08) (Linear)
+  ~= : -0.000019x^5 + 0.000049x^4 + -0.000044x^3 + 0.000016x^2 + 0.999998x (Max error: 8.941e-08)
   B2 : 16-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 6e-08) (Linear)
+  ~= : -0.000019x^5 + 0.000049x^4 + -0.000044x^3 + 0.000016x^2 + 0.999998x (Max error: 8.941e-08)
 252 random bytes transformed to linear XYZD50 bytes:
 	101b21 382210 0c0d06 1a1318 1b1205 18210c 231e11
 	26243c 000102 101514 232e4a 492f21 2c2d1e 030201
diff --git a/profiles/misc/DisplayCal_ASUS_NonMonotonic.icc.txt b/profiles/misc/DisplayCal_ASUS_NonMonotonic.icc.txt
index 552b10c..6f3df21 100644
--- a/profiles/misc/DisplayCal_ASUS_NonMonotonic.icc.txt
+++ b/profiles/misc/DisplayCal_ASUS_NonMonotonic.icc.txt
@@ -32,10 +32,13 @@
 
 rTRC : 16-bit table with 256 entries
   ~= : 2.0009, 1.11115, -0.1145, 0.0357977, 0.117647, 0.00394287, 0  (Max error: 0.011) (D-gap: -6.4e-06)
+  ~= : 0.851401x^5 + -2.137097x^4 + 1.988512x^3 + 0.362133x^2 + -0.064948x (Max error: 0.009223)
 gTRC : 16-bit table with 256 entries
   ~= : 2.27405, 0.980809, 0.0314213, 0.0311284, 0.192157, -0.0259428, 0  (Max error: 0.0038) (D-gap: 5.7e-07)
+  ~= : 0.726261x^5 + -1.862894x^4 + 1.766391x^3 + 0.445141x^2 + -0.074900x (Max error: 0.006649)
 bTRC : 16-bit table with 256 entries
   ~= : 2.19998, 1.0228, -0.0143508, 0.00389105, 0.160784, -0.014793, 0  (Max error: 0.004) (D-gap: 4.3e-07)
+  ~= : 0.043548x^5 + -0.220751x^4 + 0.414077x^3 + 0.886415x^2 + -0.123289x (Max error: 0.004746)
  XYZ : | 0.436737061 0.380325317 0.147140503 |
        | 0.217636108 0.729843140 0.052520752 |
        | 0.002655029 0.064407349 0.757827759 |
@@ -43,10 +46,13 @@
  "A" : 3 inputs
   A0 : 16-bit table with 2049 entries
   ~= : 1.00376, 0.999203, 0.014153, 1.00002, 0.125, -0.0130375, 0  (Max error: 0.018) (D-gap: -1.2e-05)
+  ~= : 0.005055x^5 + 0.024816x^4 + -0.074171x^3 + 0.059062x^2 + 0.985237x (Max error: 0.01704)
   A1 : 16-bit table with 2049 entries
   ~= : 1.00313, 0.999434, -0.00321463, 1.00002, 0.125, 0.00408629, 0  (Max error: 0.016) (D-gap: -1e-06)
+  ~= : -0.050329x^5 + 0.177154x^4 + -0.224223x^3 + 0.121108x^2 + 0.976289x (Max error: 0.01486)
   A2 : 16-bit table with 2049 entries
   ~= : 1.00655, 0.995309, 0.359156, 1.00002, 0.03125, -0.356609, 0  (Max error: 0.019) (D-gap: 4.6e-06)
+  ~= : -0.283418x^5 + 0.791348x^4 + -0.794703x^3 + 0.337955x^2 + 0.948818x (Max error: 0.0172)
 CLUT : 33 x 33 x 33 (16 bpp)
  "B" : 3 outputs
   B0 : 16-bit table with 2 entries
diff --git a/profiles/misc/Dot_Gain_20_Grayscale.icc.txt b/profiles/misc/Dot_Gain_20_Grayscale.icc.txt
index 941daa4..15e324c 100644
--- a/profiles/misc/Dot_Gain_20_Grayscale.icc.txt
+++ b/profiles/misc/Dot_Gain_20_Grayscale.icc.txt
@@ -13,10 +13,13 @@
 
 rTRC : 16-bit table with 256 entries
   ~= : 1.73713, 0.999983, 6.48912e-05, 0.0629053, 0.0235294, -1.0356e-05, 0  (Max error: 8e-05) (D-gap: -9.4e-09)
+  ~= : -0.218131x^5 + 0.708490x^4 + -0.982463x^3 + 1.442272x^2 + 0.049831x (Max error: 0.0005135)
 gTRC : 16-bit table with 256 entries
   ~= : 1.73713, 0.999983, 6.48912e-05, 0.0629053, 0.0235294, -1.0356e-05, 0  (Max error: 8e-05) (D-gap: -9.4e-09)
+  ~= : -0.218131x^5 + 0.708490x^4 + -0.982463x^3 + 1.442272x^2 + 0.049831x (Max error: 0.0005135)
 bTRC : 16-bit table with 256 entries
   ~= : 1.73713, 0.999983, 6.48912e-05, 0.0629053, 0.0235294, -1.0356e-05, 0  (Max error: 8e-05) (D-gap: -9.4e-09)
+  ~= : -0.218131x^5 + 0.708490x^4 + -0.982463x^3 + 1.442272x^2 + 0.049831x (Max error: 0.0005135)
  XYZ : | 0.964202881 0.000000000 0.000000000 |
        | 0.000000000 1.000000000 0.000000000 |
        | 0.000000000 0.000000000 0.824905396 |
diff --git a/profiles/misc/HD_709.icc.txt b/profiles/misc/HD_709.icc.txt
index bf72f84..1fad1ef 100644
--- a/profiles/misc/HD_709.icc.txt
+++ b/profiles/misc/HD_709.icc.txt
@@ -25,10 +25,13 @@
 
 rTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120847x^5 + -0.414107x^4 + 0.791163x^3 + 0.455536x^2 + 0.046562x (Max error: 0.00185)
 gTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120847x^5 + -0.414107x^4 + 0.791163x^3 + 0.455536x^2 + 0.046562x (Max error: 0.00185)
 bTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120847x^5 + -0.414107x^4 + 0.791163x^3 + 0.455536x^2 + 0.046562x (Max error: 0.00185)
  XYZ : | 0.358963013 0.446350098 0.158889771 |
        | 0.195922852 0.742843628 0.061233521 |
        | 0.009674072 0.043518066 0.771713257 |
diff --git a/profiles/misc/Japan_Color_2001_Coated.icc.txt b/profiles/misc/Japan_Color_2001_Coated.icc.txt
index 24f81a2..ed7edc4 100644
--- a/profiles/misc/Japan_Color_2001_Coated.icc.txt
+++ b/profiles/misc/Japan_Color_2001_Coated.icc.txt
@@ -20,12 +20,16 @@
  "A" : 4 inputs
   A0 : 16-bit table with 256 entries
   ~= : 1.2043, 0.854942, 0.610626, 0.525292, 0.00392157, -0.550543, 0  (Max error: 0.034) (D-gap: 0.0031)
+  ~= : -0.649351x^5 + 1.188296x^4 + -0.941728x^3 + 0.583173x^2 + 0.819610x (Max error: 0.002437)
   A1 : 16-bit table with 256 entries
   ~= : 1.10615, 1.02819, -0.00403214, 0.350195, 0.00392157, 0.0344724, 0  (Max error: 0.061) (D-gap: 0.033)
+  ~= : -0.213030x^5 + 0.381146x^4 + -0.463068x^3 + 0.576219x^2 + 0.718732x (Max error: 0.003266)
   A2 : 16-bit table with 256 entries
   ~= : 1.1484, 0.997667, 0.0234146, 0.619326, 0.0235294, -0.015198, 0  (Max error: 0.009) (D-gap: 4.4e-06)
+  ~= : -0.113626x^5 + 0.171895x^4 + -0.252260x^3 + 0.459814x^2 + 0.734178x (Max error: 0.003866)
   A3 : 16-bit table with 256 entries
   ~= : 3.37872, 0.28468, 0.859486, 0.322957, 0.00392157, -0.559585, 0  (Max error: 0.043) (D-gap: 0.041)
+  ~= : -0.838756x^5 + 2.086855x^4 + -1.778941x^3 + 0.943068x^2 + 0.587774x (Max error: 0.01034)
 CLUT : 9 x 9 x 9 x 9 (16 bpp)
  "B" : 3 outputs
   B0 : 16-bit table with 2 entries
diff --git a/profiles/misc/Kodak_sRGB.icc.txt b/profiles/misc/Kodak_sRGB.icc.txt
index a53d5ef..4a5dfb4 100644
--- a/profiles/misc/Kodak_sRGB.icc.txt
+++ b/profiles/misc/Kodak_sRGB.icc.txt
@@ -22,26 +22,35 @@
 
 rTRC : 16-bit table with 256 entries
   ~= : 2.41906, 0.940164, 0.0585121, 0.0696852, 0.0431373, 0.00320272, 0.00392157  (Max error: 0.00044) (D-gap: -1e-07)
+  ~= : 0.343995x^5 + -1.043788x^4 + 1.449500x^3 + 0.140272x^2 + 0.110022x (Max error: 0.003922)
 gTRC : 16-bit table with 256 entries
   ~= : 2.41906, 0.940164, 0.0585121, 0.0696852, 0.0431373, 0.00320272, 0.00392157  (Max error: 0.00044) (D-gap: -1e-07)
+  ~= : 0.343995x^5 + -1.043788x^4 + 1.449500x^3 + 0.140272x^2 + 0.110022x (Max error: 0.003922)
 bTRC : 16-bit table with 256 entries
   ~= : 2.41906, 0.940164, 0.0585121, 0.0696852, 0.0431373, 0.00320272, 0.00392157  (Max error: 0.00044) (D-gap: -1e-07)
+  ~= : 0.343995x^5 + -1.043788x^4 + 1.449500x^3 + 0.140272x^2 + 0.110022x (Max error: 0.003922)
  XYZ : | 0.437637329 0.388412476 0.142410278 |
        | 0.214950562 0.712905884 0.072128296 |
        | 0.011260986 0.080718994 0.725875854 |
  A2B : "A", CLUT, "B"
  "A" : 3 inputs
   A0 : 16-bit table with 256 entries
+  ~= : -2.079725x^5 + 5.833611x^4 + -5.880472x^3 + 2.367612x^2 + 0.758975x (Max error: 0.008862)
   A1 : 16-bit table with 256 entries
+  ~= : -2.079725x^5 + 5.833611x^4 + -5.880472x^3 + 2.367612x^2 + 0.758975x (Max error: 0.008862)
   A2 : 16-bit table with 256 entries
+  ~= : -2.079725x^5 + 5.833611x^4 + -5.880472x^3 + 2.367612x^2 + 0.758975x (Max error: 0.008862)
 CLUT : 8 x 8 x 8 (16 bpp)
  "B" : 3 outputs
   B0 : 16-bit table with 4096 entries
   ~= : 4.65661e-07, 6.0642, -6.04012, 1, 0.996337, -0.003668, 0  (Max error: 1.7e-05) (D-gap: 9.4e-06)
+  ~= : 0.014232x^5 + -0.035877x^4 + 0.031439x^3 + -0.011046x^2 + 1.001253x (Max error: 0.003662)
   B1 : 16-bit table with 4096 entries
   ~= : 4.65661e-07, 6.0642, -6.04012, 1, 0.996337, -0.003668, 0  (Max error: 1.7e-05) (D-gap: 9.4e-06)
+  ~= : 0.014232x^5 + -0.035877x^4 + 0.031439x^3 + -0.011046x^2 + 1.001253x (Max error: 0.003662)
   B2 : 16-bit table with 4096 entries
   ~= : 4.65661e-07, 6.0642, -6.04012, 1, 0.996337, -0.003668, 0  (Max error: 1.7e-05) (D-gap: 9.4e-06)
+  ~= : 0.014232x^5 + -0.035877x^4 + 0.031439x^3 + -0.011046x^2 + 1.001253x (Max error: 0.003662)
 252 random bytes transformed to linear XYZD50 bytes:
 	355632 a5d31d 4c6517 190f30 1e124a 5d4709 4e8727
 	693a2f 1c1712 6c4626 a0a014 4d5d0c 2e442c 42288e
diff --git a/profiles/misc/Lexmark_X110.icc.txt b/profiles/misc/Lexmark_X110.icc.txt
index ae5468f..792af03 100644
--- a/profiles/misc/Lexmark_X110.icc.txt
+++ b/profiles/misc/Lexmark_X110.icc.txt
@@ -16,18 +16,24 @@
  "A" : 3 inputs
   A0 : 8-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 0) (Linear)
+  ~= : -0.000002x^5 + 0.000006x^4 + -0.000005x^3 + 0.000002x^2 + 1.000000x (Max error: 1.788e-07)
   A1 : 8-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 0) (Linear)
+  ~= : -0.000002x^5 + 0.000006x^4 + -0.000005x^3 + 0.000002x^2 + 1.000000x (Max error: 1.788e-07)
   A2 : 8-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 0) (Linear)
+  ~= : -0.000002x^5 + 0.000006x^4 + -0.000005x^3 + 0.000002x^2 + 1.000000x (Max error: 1.788e-07)
 CLUT : 17 x 17 x 17 (8 bpp)
  "B" : 3 outputs
   B0 : 8-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 0) (Linear)
+  ~= : -0.000002x^5 + 0.000006x^4 + -0.000005x^3 + 0.000002x^2 + 1.000000x (Max error: 1.788e-07)
   B1 : 8-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 0) (Linear)
+  ~= : -0.000002x^5 + 0.000006x^4 + -0.000005x^3 + 0.000002x^2 + 1.000000x (Max error: 1.788e-07)
   B2 : 8-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 0) (Linear)
+  ~= : -0.000002x^5 + 0.000006x^4 + -0.000005x^3 + 0.000002x^2 + 1.000000x (Max error: 1.788e-07)
 252 random bytes transformed to linear XYZD50 bytes:
 	6fa094 d8f243 a7d043 825cbe 8365c0 a39f15 5c8161
 	a871bd 5a5249 aa8b81 d2f028 a6cb1b 729e83 937fb7
diff --git a/profiles/misc/MartiMaria_browsertest_HARD.icc.txt b/profiles/misc/MartiMaria_browsertest_HARD.icc.txt
index afd1a1f..b5ef40a 100644
--- a/profiles/misc/MartiMaria_browsertest_HARD.icc.txt
+++ b/profiles/misc/MartiMaria_browsertest_HARD.icc.txt
@@ -19,9 +19,12 @@
  'A2B2' : 'mft2' :  29554 : 2184
 
 rTRC : 16-bit table with 255 entries
+  ~= : 11.378673x^5 + -39.503075x^4 + 52.381248x^3 + -32.764713x^2 + 9.507866x (Max error: 0.2382)
 gTRC : 16-bit table with 255 entries
   ~= : 1, 0.00387579, 0, 0, 0, 0, 0  (Max error: 2.3e-10)
+  ~= : 65.688660x^5 + -143.307236x^4 + 107.468880x^3 + -31.838594x^2 + 2.988291x (Max error: 0.9961)
 bTRC : 16-bit table with 255 entries
+  ~= : 11.378673x^5 + -39.503075x^4 + 52.381248x^3 + -32.764713x^2 + 9.507866x (Max error: 0.2382)
  XYZ : | 0.964202881 0.000000000 0.964202881 |
        | 1.000000000 0.000000000 1.000000000 |
        | 0.824905396 0.000000000 0.824905396 |
diff --git a/profiles/misc/Phase_One_P25.icc.txt b/profiles/misc/Phase_One_P25.icc.txt
index e6b9ce9..31e82ba 100644
--- a/profiles/misc/Phase_One_P25.icc.txt
+++ b/profiles/misc/Phase_One_P25.icc.txt
@@ -20,17 +20,23 @@
 
 rTRC : 16-bit table with 256 entries
   ~= : 0.557427, 0.823753, -0.0355345, 3.73293, 0.0431373, 0.142111, 0  (Max error: 0.019) (D-gap: -0.019)
+  ~= : 10.371853x^5 + -29.808578x^4 + 31.703903x^3 + -15.693880x^2 + 4.426702x (Max error: 0.01161)
 gTRC : 16-bit table with 256 entries
   ~= : 0.400724, 1.03417, -0.022065, 5.60534, 0.027451, 0.0223994, 0  (Max error: 0.027) (D-gap: -1.7e-05)
+  ~= : 16.163185x^5 + -45.403114x^4 + 46.883369x^3 + -22.263912x^2 + 5.620472x (Max error: 0.0367)
 bTRC : 16-bit table with 256 entries
+  ~= : 4.839172x^5 + -15.317191x^4 + 18.225716x^3 + -10.121508x^2 + 3.373812x (Max error: 0.01237)
  XYZ : | 0.647903442 0.357360840 0.156417847 |
        | 0.382919312 1.109725952 0.000000000 |
        | 0.083267212 0.679275513 0.523422241 |
  A2B : "A", CLUT, "B"
  "A" : 3 inputs
   A0 : 16-bit table with 256 entries
+  ~= : 20.854698x^5 + -59.823750x^4 + 63.662682x^3 + -30.689857x^2 + 6.996227x (Max error: 0.09414)
   A1 : 16-bit table with 256 entries
+  ~= : 20.854698x^5 + -59.823750x^4 + 63.662682x^3 + -30.689857x^2 + 6.996227x (Max error: 0.09414)
   A2 : 16-bit table with 256 entries
+  ~= : 20.854698x^5 + -59.823750x^4 + 63.662682x^3 + -30.689857x^2 + 6.996227x (Max error: 0.09414)
 CLUT : 33 x 33 x 33 (16 bpp)
  "B" : 3 outputs
   B0 : 16-bit table with 2 entries
diff --git a/profiles/misc/PrintOpen_ISO_Coated_CMYK.icc.txt b/profiles/misc/PrintOpen_ISO_Coated_CMYK.icc.txt
index 42975ed..6fe62fb 100644
--- a/profiles/misc/PrintOpen_ISO_Coated_CMYK.icc.txt
+++ b/profiles/misc/PrintOpen_ISO_Coated_CMYK.icc.txt
@@ -23,20 +23,27 @@
  "A" : 4 inputs
   A0 : 16-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 6e-08) (Linear)
+  ~= : -0.000019x^5 + 0.000049x^4 + -0.000044x^3 + 0.000016x^2 + 0.999998x (Max error: 8.941e-08)
   A1 : 16-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 6e-08) (Linear)
+  ~= : -0.000019x^5 + 0.000049x^4 + -0.000044x^3 + 0.000016x^2 + 0.999998x (Max error: 8.941e-08)
   A2 : 16-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 6e-08) (Linear)
+  ~= : -0.000019x^5 + 0.000049x^4 + -0.000044x^3 + 0.000016x^2 + 0.999998x (Max error: 8.941e-08)
   A3 : 16-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 6e-08) (Linear)
+  ~= : -0.000019x^5 + 0.000049x^4 + -0.000044x^3 + 0.000016x^2 + 0.999998x (Max error: 8.941e-08)
 CLUT : 16 x 16 x 16 x 16 (16 bpp)
  "B" : 3 outputs
   B0 : 16-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 6e-08) (Linear)
+  ~= : -0.000019x^5 + 0.000049x^4 + -0.000044x^3 + 0.000016x^2 + 0.999998x (Max error: 8.941e-08)
   B1 : 16-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 6e-08) (Linear)
+  ~= : -0.000019x^5 + 0.000049x^4 + -0.000044x^3 + 0.000016x^2 + 0.999998x (Max error: 8.941e-08)
   B2 : 16-bit table with 256 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 6e-08) (Linear)
+  ~= : -0.000019x^5 + 0.000049x^4 + -0.000044x^3 + 0.000016x^2 + 0.999998x (Max error: 8.941e-08)
 252 random bytes transformed to linear XYZD50 bytes:
 	162328 3a2310 090a05 1d151d 1b1306 18230c 211b10
 	2a2742 000101 101615 253047 4c3123 27291b 020201
diff --git a/profiles/misc/SWOP_Coated_20_GCR_CMYK.icc.txt b/profiles/misc/SWOP_Coated_20_GCR_CMYK.icc.txt
index daca625..04c19ba 100644
--- a/profiles/misc/SWOP_Coated_20_GCR_CMYK.icc.txt
+++ b/profiles/misc/SWOP_Coated_20_GCR_CMYK.icc.txt
@@ -20,9 +20,13 @@
  A2B : "A", CLUT, "B"
  "A" : 4 inputs
   A0 : 16-bit table with 256 entries
+  ~= : -3.929942x^5 + 8.898722x^4 + -6.667570x^3 + 2.135816x^2 + 0.562974x (Max error: 0.02075)
   A1 : 16-bit table with 256 entries
+  ~= : -2.251796x^5 + 5.479708x^4 + -4.236609x^3 + 1.464926x^2 + 0.543770x (Max error: 0.02226)
   A2 : 16-bit table with 256 entries
+  ~= : -2.251796x^5 + 5.479708x^4 + -4.236609x^3 + 1.464926x^2 + 0.543770x (Max error: 0.02226)
   A3 : 16-bit table with 256 entries
+  ~= : -2.251796x^5 + 5.479708x^4 + -4.236609x^3 + 1.464926x^2 + 0.543770x (Max error: 0.02226)
 CLUT : 16 x 16 x 16 x 16 (16 bpp)
  "B" : 3 outputs
   B0 : 16-bit table with 2 entries
diff --git a/profiles/misc/US_Web_Coated_SWOP_CMYK.icc.txt b/profiles/misc/US_Web_Coated_SWOP_CMYK.icc.txt
index 7e2e9ad..2d39eb8 100644
--- a/profiles/misc/US_Web_Coated_SWOP_CMYK.icc.txt
+++ b/profiles/misc/US_Web_Coated_SWOP_CMYK.icc.txt
@@ -20,12 +20,16 @@
  "A" : 4 inputs
   A0 : 16-bit table with 256 entries
   ~= : 0.642081, 1.93472, 1.00137, 1.84533, 0.0156863, -0.991272, 0  (Max error: 0.0056) (D-gap: -2.3e-05)
+  ~= : 0.133682x^5 + -0.664160x^4 + 1.055095x^3 + -0.883181x^2 + 1.358564x (Max error: 0.008396)
   A1 : 16-bit table with 256 entries
   ~= : 0.97251, 1.02769, 1.19953, 1.62257, 0.0156863, -1.18274, 0  (Max error: 0.0073) (D-gap: 0.00084)
+  ~= : -0.104087x^5 + 0.149279x^4 + 0.159902x^3 + -0.322116x^2 + 1.117021x (Max error: 0.0087)
   A2 : 16-bit table with 256 entries
   ~= : 1.03739, 0.967143, 0.737392, 2.01167, 0.00392157, -0.725022, 0  (Max error: 0.014) (D-gap: 1.8e-05)
+  ~= : -1.099879x^5 + 1.832695x^4 + -0.567654x^3 + -0.289482x^2 + 1.124320x (Max error: 0.00968)
   A3 : 16-bit table with 256 entries
   ~= : 1.12285, 0.822891, 0.770402, 1.84047, 0.00392157, -0.742872, 0  (Max error: 0.056) (D-gap: -0.00049)
+  ~= : 0.739130x^5 + -1.539747x^4 + 1.399725x^3 + -0.690077x^2 + 1.090969x (Max error: 0.008234)
 CLUT : 9 x 9 x 9 x 9 (16 bpp)
  "B" : 3 outputs
   B0 : 16-bit table with 2 entries
diff --git a/profiles/misc/XRite_GRACol7_340_CMYK.icc.txt b/profiles/misc/XRite_GRACol7_340_CMYK.icc.txt
index e733cf7..f8dfe9b 100644
--- a/profiles/misc/XRite_GRACol7_340_CMYK.icc.txt
+++ b/profiles/misc/XRite_GRACol7_340_CMYK.icc.txt
@@ -24,20 +24,27 @@
  "A" : 4 inputs
   A0 : 16-bit table with 4096 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 7.7e-06) (Linear)
+  ~= : 0.013998x^5 + -0.035322x^4 + 0.030987x^3 + -0.010902x^2 + 1.001239x (Max error: 5.007e-05)
   A1 : 16-bit table with 4096 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 7.7e-06) (Linear)
+  ~= : 0.013998x^5 + -0.035322x^4 + 0.030987x^3 + -0.010902x^2 + 1.001239x (Max error: 5.007e-05)
   A2 : 16-bit table with 4096 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 7.7e-06) (Linear)
+  ~= : 0.013998x^5 + -0.035322x^4 + 0.030987x^3 + -0.010902x^2 + 1.001239x (Max error: 5.007e-05)
   A3 : 16-bit table with 4096 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 7.7e-06) (Linear)
+  ~= : 0.013998x^5 + -0.035322x^4 + 0.030987x^3 + -0.010902x^2 + 1.001239x (Max error: 5.007e-05)
 CLUT : 17 x 17 x 17 x 17 (16 bpp)
  "B" : 3 outputs
   B0 : 16-bit table with 4096 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 7.7e-06) (Linear)
+  ~= : 0.013998x^5 + -0.035322x^4 + 0.030987x^3 + -0.010902x^2 + 1.001239x (Max error: 5.007e-05)
   B1 : 16-bit table with 4096 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 7.7e-06) (Linear)
+  ~= : 0.013998x^5 + -0.035322x^4 + 0.030987x^3 + -0.010902x^2 + 1.001239x (Max error: 5.007e-05)
   B2 : 16-bit table with 4096 entries
   ~= : 1, 1, 0, 0, 0, 0, 0  (Max error: 7.7e-06) (Linear)
+  ~= : 0.013998x^5 + -0.035322x^4 + 0.030987x^3 + -0.010902x^2 + 1.001239x (Max error: 5.007e-05)
 252 random bytes transformed to linear XYZD50 bytes:
 	121d23 3b2510 0c0e07 1c151b 1e1607 17210e 252013
 	242239 010102 111616 212b45 493020 26281a 030201
diff --git a/profiles/misc/sRGB_HP.icc.txt b/profiles/misc/sRGB_HP.icc.txt
index 2fc77eb..79d6e4d 100644
--- a/profiles/misc/sRGB_HP.icc.txt
+++ b/profiles/misc/sRGB_HP.icc.txt
@@ -25,10 +25,13 @@
 
 rTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 gTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 bTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
  XYZ : | 0.436065674 0.385147095 0.143066406 |
        | 0.222488403 0.716873169 0.060607910 |
        | 0.013916016 0.097076416 0.714096069 |
diff --git a/profiles/misc/sRGB_HP_2.icc.txt b/profiles/misc/sRGB_HP_2.icc.txt
index dc48f17..cf8f11d 100644
--- a/profiles/misc/sRGB_HP_2.icc.txt
+++ b/profiles/misc/sRGB_HP_2.icc.txt
@@ -25,10 +25,13 @@
 
 rTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 gTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 bTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
  XYZ : | 0.436065674 0.385147095 0.143066406 |
        | 0.222488403 0.716873169 0.060607910 |
        | 0.013916016 0.097076416 0.714096069 |
diff --git a/profiles/misc/sRGB_black_scaled.icc.txt b/profiles/misc/sRGB_black_scaled.icc.txt
index b6f8d17..051cf35 100644
--- a/profiles/misc/sRGB_black_scaled.icc.txt
+++ b/profiles/misc/sRGB_black_scaled.icc.txt
@@ -24,10 +24,13 @@
 
 rTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 gTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 bTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
  XYZ : | 0.436065674 0.385147095 0.143066406 |
        | 0.222488403 0.716873169 0.060607910 |
        | 0.013916016 0.097076416 0.714096069 |
diff --git a/profiles/mobile/Display_P3_LUT.icc.txt b/profiles/mobile/Display_P3_LUT.icc.txt
index ef1d926..789510d 100644
--- a/profiles/mobile/Display_P3_LUT.icc.txt
+++ b/profiles/mobile/Display_P3_LUT.icc.txt
@@ -19,10 +19,13 @@
 
 rTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 gTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 bTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
  XYZ : | 0.515121460 0.291976929 0.157104492 |
        | 0.241195679 0.692245483 0.066574097 |
        | -0.001037598 0.041885376 0.784072876 |
diff --git a/profiles/mobile/sRGB_LUT.icc.txt b/profiles/mobile/sRGB_LUT.icc.txt
index 2f8d841..d8a9007 100644
--- a/profiles/mobile/sRGB_LUT.icc.txt
+++ b/profiles/mobile/sRGB_LUT.icc.txt
@@ -19,10 +19,13 @@
 
 rTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 gTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
 bTRC : 16-bit table with 1024 entries
   ~= : 2.39936, 0.948025, 0.0519888, 0.0777105, 0.0449658, 7.48783e-06, 0  (Max error: 5.7e-05) (D-gap: 4.4e-06)
+  ~= : 0.120918x^5 + -0.414292x^4 + 0.791333x^3 + 0.455472x^2 + 0.046569x (Max error: 0.00185)
  XYZ : | 0.436035156 0.385116577 0.143051147 |
        | 0.222488403 0.716903687 0.060607910 |
        | 0.013916016 0.097061157 0.713912964 |
diff --git a/profiles/sRGB_Facebook.icc.txt b/profiles/sRGB_Facebook.icc.txt
index 4657851..d2e0238 100644
--- a/profiles/sRGB_Facebook.icc.txt
+++ b/profiles/sRGB_Facebook.icc.txt
@@ -18,10 +18,13 @@
 
 rTRC : 16-bit table with 26 entries
   ~= : 2.39736, 0.949206, 0.050643, 0.0774395, 0.04, 9.82733e-05, 0  (Max error: 0.00025) (D-gap: -1.8e-06)
+  ~= : 2.981522x^5 + -6.815283x^4 + 5.674999x^3 + -1.015081x^2 + 0.173843x (Max error: 0.05446)
 gTRC : 16-bit table with 26 entries
   ~= : 2.39736, 0.949206, 0.050643, 0.0774395, 0.04, 9.82733e-05, 0  (Max error: 0.00025) (D-gap: -1.8e-06)
+  ~= : 2.981522x^5 + -6.815283x^4 + 5.674999x^3 + -1.015081x^2 + 0.173843x (Max error: 0.05446)
 bTRC : 16-bit table with 26 entries
   ~= : 2.39736, 0.949206, 0.050643, 0.0774395, 0.04, 9.82733e-05, 0  (Max error: 0.00025) (D-gap: -1.8e-06)
+  ~= : 2.981522x^5 + -6.815283x^4 + 5.674999x^3 + -1.015081x^2 + 0.173843x (Max error: 0.05446)
  XYZ : | 0.436065674 0.385147095 0.143066406 |
        | 0.222488403 0.716873169 0.060607910 |
        | 0.013916016 0.097076416 0.714096069 |
diff --git a/skcms.c b/skcms.c
index d132e3a..cc2d6a6 100644
--- a/skcms.c
+++ b/skcms.c
@@ -7,8 +7,10 @@
 
 // skcms.c is a unity build target for skcms, #including every other C source file.
 
+#include "src/GaussNewton.c"
 #include "src/ICCProfile.c"
 #include "src/LinearAlgebra.c"
 #include "src/PortableMath.c"
+#include "src/TF15.c"
 #include "src/TransferFunction.c"
 #include "src/Transform.c"
diff --git a/skcms.h b/skcms.h
index 152ba51..027d531 100644
--- a/skcms.h
+++ b/skcms.h
@@ -109,6 +109,14 @@
 bool skcms_ApproximateCurve(const skcms_Curve* curve, skcms_TransferFunction* approx,
                             float* max_error);
 
+// A specialized approximation for transfer functions with gamma between 1 and 5.
+//     f(x) = Ax^5 + Bx^4 + Cx^3 + Dx^2 + (1 - A - B - C - D)x
+typedef struct {
+    float A,B,C,D;
+} skcms_TF15;
+
+bool skcms_ApproximateCurve15(const skcms_Curve* curve, skcms_TF15* approx, float* max_error);
+
 typedef struct {
     uint32_t       signature;
     uint32_t       type;
diff --git a/src/GaussNewton.c b/src/GaussNewton.c
new file mode 100644
index 0000000..94b0c21
--- /dev/null
+++ b/src/GaussNewton.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "../skcms.h"
+#include "GaussNewton.h"
+#include "LinearAlgebra.h"
+#include <assert.h>
+
+bool skcms_gauss_newton_step(float (*     t)(float x, const void*), const void* t_ctx,
+                             float (*     f)(float x, const float    P[4]),
+                             void  (*grad_f)(float x,       float dfdP[4]),
+                             float P[4],
+                             float x0, float x1, int N,
+                             void  (*fixup)(skcms_Matrix4x4*, const float P[4])) {
+    // We'll sample x from the range [x0,x1] (both inclusive) N times with even spacing.
+    //
+    // We want to do P' = P + (Jf^T Jf)^-1 Jf^T r(P),
+    //   where r(P) is the residual vector t(x) - f(x,P)
+    //   and Jf is the Jacobian matrix of f(), ∂r/∂P.
+    //
+    // Let's review the shape of each of these expressions:
+    //   r(P)   is [N x 1], a column vector with one entry per value of x tested
+    //   Jf     is [N x 4], a matrix with an entry for each (x,P) pair
+    //   Jf^T   is [4 x N], the transpose of Jf
+    //
+    //   Jf^T Jf   is [4 x N] * [N x 4] == [4 x 4], a 4x4 matrix,
+    //                                              and so is its inverse (Jf^T Jf)^-1
+    //   Jf^T r(P) is [4 x N] * [N x 1] == [4 x 1], a column vector with the same shape as P
+    //
+    // Our implementation strategy to get to the final ∆P is
+    //   1) evaluate Jf^T Jf,   call that lhs
+    //   2) evaluate Jf^T r(P), call that rhs
+    //   3) invert lhs
+    //   4) multiply inverse lhs by rhs
+    //
+    // This is a friendly implementation strategy because we don't have to have any
+    // buffers that scale with N, and equally nice don't have to perform any matrix
+    // operations that are variable size.
+    //
+    // Other implementation strategies could trade this off, e.g. evaluating the
+    // pseudoinverse of Jf ( (Jf^T Jf)^-1 Jf^T ) directly, then multiplying that by
+    // the residuals.  That would probably require implementing singular value
+    // decomposition, and would create a [4 x N] matrix to be multiplied by the
+    // [N x 1] residual vector, but on the upside I think that'd eliminate the
+    // possibility of this skcms_gauss_newton_step() function ever failing.
+
+    // 0) start off with lhs and rhs safely zeroed.
+    skcms_Matrix4x4 lhs = {{ {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} }};
+    skcms_Vector4   rhs = {  {0,0,0,0} };
+
+    // 1,2) evaluate lhs and evaluate rhs
+    //   We want to evaluate Jf only once, but both lhs and rhs involve Jf^T,
+    //   so we'll have to update lhs and rhs at the same time.
+    float dx = (x1-x0)/(N-1);
+    for (int i = 0; i < N; i++) {
+        float x = x0 + i*dx;
+
+        float resid = t(x,t_ctx) - f(x,P);
+
+        float dfdP[4] = {0,0,0,0};
+        grad_f(x, dfdP);
+
+        // TODO: allow a bias(x) function?
+        // As-is, this bias(x) can be folded into t(x), f(x), and grad_f(x).
+    #if 0
+        float b = bias(x, bias_ctx);
+        resid   *= b;
+        dfdP[0] *= b;
+        dfdP[1] *= b;
+        dfdP[2] *= b;
+        dfdP[3] *= b;
+    #endif
+
+        for (int r = 0; r < 4; r++) {
+            for (int c = 0; c < 4; c++) {
+                lhs.vals[r][c] += dfdP[r] * dfdP[c];
+            }
+            rhs.vals[r] += dfdP[r] * resid;
+        }
+    }
+
+    // 3) invert lhs
+    if (fixup) {
+        fixup(&lhs, P);
+    }
+    skcms_Matrix4x4 lhs_inv;
+    if (!skcms_Matrix4x4_invert(&lhs, &lhs_inv)) {
+        return false;
+    }
+
+    // 4) multiply inverse lhs by rhs
+    skcms_Vector4 dP = skcms_Matrix4x4_Vector4_mul(&lhs_inv, &rhs);
+    P[0] += dP.vals[0];
+    P[1] += dP.vals[1];
+    P[2] += dP.vals[2];
+    P[3] += dP.vals[3];
+    return true;
+}
diff --git a/src/GaussNewton.h b/src/GaussNewton.h
new file mode 100644
index 0000000..dfd7fe7
--- /dev/null
+++ b/src/GaussNewton.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include "LinearAlgebra.h"
+
+// One Gauss-Newton step, tuning up to 4 parameters P to minimize [ t(x,ctx) - f(x,P) ]^2.
+//
+//   t:        target function of x to approximate
+//   t_ctx:    any context needed for t, passed blindly into calls to t()
+//   f:        function of x,P we're tuning to match t()
+//   grad_f:   gradient of f() at x
+//   P:        in-out, both your initial guess for parameters of f(), and our updated values
+//   x0,x1,N:  N x-values to test in [x0,x1] (both inclusive) with even spacing
+//   fixup:    an optional hook to tweak the Jf^T Jf matrix (given P) before we invert it
+//
+// If you have fewer than 4 parameters, set the unused P to zero, don't touch their dfdP,
+// and use fixup() to set 1 along their diagonal entries.
+//
+// Returns true and updates P on success, or returns false on failure.
+bool skcms_gauss_newton_step(float (*     t)(float x, const void*), const void* t_ctx,
+                             float (*     f)(float x, const float    P[4]),
+                             void  (*grad_f)(float x,       float dfdP[4]),
+                             float P[4],
+                             float x0, float x1, int N,
+                             void  (*fixup)(skcms_Matrix4x4*, const float P[4]));
diff --git a/src/TF15.c b/src/TF15.c
new file mode 100644
index 0000000..11e009b
--- /dev/null
+++ b/src/TF15.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "../skcms.h"
+#include "GaussNewton.h"
+#include "PortableMath.h"
+#include "TransferFunction.h"
+#include <limits.h>
+#include <string.h>
+
+// Evaluating skcms_TF15{A,B,C,D} at x:
+//   f(x) = Ax^5 + Bx^4 + Cx^3 + Dx^2 + (1 - A - B - C - D)x
+//
+//   ∂f/∂A = x^5 - x
+//   ∂f/∂B = x^4 - x
+//   ∂f/∂C = x^3 - x
+//   ∂f/∂D = x^2 - x
+
+static float eval_15(float x, const float P[4]) {
+    return P[0]*x*x*x*x*x
+         + P[1]*x*x*x*x
+         + P[2]*x*x*x
+         + P[3]*x*x
+         + (1 - P[0] - P[1] - P[2] - P[3]) * x;
+}
+static void grad_15(float x, float dfdP[4]) {
+    dfdP[0] = x*x*x*x*x - x;
+    dfdP[1] = x*x*x*x   - x;
+    dfdP[2] = x*x*x     - x;
+    dfdP[3] = x*x       - x;
+}
+
+static float eval_curve(float x, const void* vctx) {
+    const skcms_Curve* curve = (const skcms_Curve*)vctx;
+
+    if (curve->table_entries == 0) {
+        return skcms_TransferFunction_eval(&curve->parametric, x);
+    }
+
+    // TODO: today we should always hit an entry exactly, but if that changes, lerp?
+    int ix = (int)( x * (curve->table_entries - 1) );
+
+    if (curve->table_8) {
+        return curve->table_8[ix] * (1/255.0f);
+    } else {
+        uint16_t be;
+        memcpy(&be, curve->table_16 + 2*ix, 2);
+
+        uint16_t le = ((be << 8) | (be >> 8)) & 0xffff;
+        return le * (1/65535.0f);
+    }
+}
+
+bool skcms_ApproximateCurve15(const skcms_Curve* curve, skcms_TF15* approx, float* max_error) {
+    // Start a guess at skcms_TF15{0,0,1}, i.e. f(x) = x^2, i.e. gamma = 2.
+    // TODO: guess better somehow, like we do in skcms_ApproximateCurve()?
+    float P[4] = { 0,0,1, 0 };
+
+    if (curve->table_entries > (uint32_t)INT_MAX) {
+        // That's just crazy.
+        return false;
+    }
+    const int N = curve->table_entries == 0 ? 257 /*TODO: tune?*/
+                                            : (int)curve->table_entries;
+
+    for (int i = 0; i < 3/*TODO: Tune???*/; i++) {
+        if (!skcms_gauss_newton_step(eval_curve, curve,
+                                     eval_15, grad_15,
+                                     P, 0,1,N,
+                                     NULL)) {
+            return false;
+        }
+    }
+
+    *max_error = 0;
+    for (int i = 0; i < N; i++) {
+        float x = i * (1.0f / (N-1));
+
+        float err = fabsf_( eval_curve(x, curve) - eval_15(x, P) );
+        if (err > *max_error) {
+            *max_error = err;
+        }
+    }
+    approx->A = P[0];
+    approx->B = P[1];
+    approx->C = P[2];
+    approx->D = P[3];
+    return true;
+}
diff --git a/test_only.c b/test_only.c
index 2c56826..ef33ad9 100644
--- a/test_only.c
+++ b/test_only.c
@@ -164,6 +164,15 @@
     fprintf(fp, "\n");
 }
 
+static void dump_approx_tf15(FILE* fp, const skcms_TF15* tf,
+                             float max_error, bool for_unit_test) {
+    (void)for_unit_test;
+    fprintf(fp, "  ~= : %fx^5 + %fx^4 + %fx^3 + %fx^2 + %fx (Max error: %.4g)\n",
+            (double)tf->A, (double)tf->B, (double)tf->C, (double)tf->D,
+            (double)(1 - tf->A - tf->B - tf->C - tf->D),
+            (double)max_error);
+}
+
 static void dump_curve(FILE* fp, const char* name, const skcms_Curve* curve, bool for_unit_test) {
     if (curve->table_entries) {
         fprintf(fp, "%4s : %d-bit table with %u entries\n", name,
@@ -173,6 +182,10 @@
         if (skcms_ApproximateCurve(curve, &tf, &max_error)) {
             dump_approx_transfer_function(fp, &tf, max_error, for_unit_test);
         }
+        skcms_TF15 tf15;
+        if (skcms_ApproximateCurve15(curve, &tf15, &max_error)) {
+            dump_approx_tf15(fp, &tf15, max_error, for_unit_test);
+        }
     } else {
         dump_transfer_function(fp, name, &curve->parametric);
     }