I had a little fun with SQL Server last week trying to normalize a gas composition function that was returning a molar percentage of the gas. During testing we found several cases where the sum of the components did not add up to 100.0%. Of course due to floating point inaccuracies it is quite possible that rounding errors could also contribute to the issue. The values we were seeing were a couple of percentage points different and so we decided to normalize the data to ensure that it added up to 100.0%. At the same time, I rounded the components (to two decimal places in molar %) since there are contractual documents specifying the precision that will be used during final calculation.
One interesting point is that if you simply round the components after the summation, the total percentage may not be 100% either. Here is an example using purely theoretical values:
| Component | Actual | Rounded |
| C1 | 10.955556 | 10.96 |
| C2 | 8.904444 | 8.90 |
| C3 | 8.904444 | 8.90 |
| iC4 | 8.904444 | 8.90 |
| nC4 | 8.904444 | 8.90 |
| iC5 | 8.904444 | 8.90 |
| nC5 | 8.904444 | 8.90 |
| C6+ | 8.904444 | 8.90 |
| N2 | 8.904444 | 8.90 |
| CO2 | 8.904444 | 8.90 |
| O2 | 8.904444 | 8.90 |
| Total | 100.000000 | 99.96 |
To account for this, I rounded all of the values except the final (chosen) component and then applied the remainder to that component. So the final normalization and rounding might look like this:
| Component | Actual | Normalized |
| C1 | 94.719559 | 95.00 |
| C2 | 3.579182 | 3.59 |
| C3 | 0.923634 | 0.93 |
| iC4 | 0.343786 | 0.34 |
| nC4 | 0.050411 | 0.05 |
| iC5 | 0.050411 | 0.05 |
| nC5 | 0.000000 | 0.00 |
| C6+ | 0.000000 | 0.00 |
| N2 | 0.040948 | 0.04 |
| CO2 | 0.000000 | 0.00 |
| O2 | 0.000000 | 0.00 |
| Total | 99.707930 | 100.00 |
IF (ABS(100.0 - @sumComponents) <= @threshold)
BEGIN
SET @diff = 100.0 - @sumComponents
SET @factor = 1.0 + (@diff / 100.0)
END
ELSE
BEGIN
-- No correction factor
SET @factor = 1.0
END
-- Round the components to 2 decimal places for molar percent
SELECT @C2 = ROUND(@C2 * @factor, 2)
,@C3 = ROUND(@C3 * @factor, 2)
,@iC4 = ROUND(@iC4 * @factor, 2)
,@nC4 = ROUND(@nC4 * @factor, 2)
,@iC5 = ROUND(@iC5 * @factor, 2)
,@nC5 = ROUND(@nC5 * @factor, 2)
,@C6 = ROUND(@C6 * @factor, 2)
,@N2 = ROUND(@N2 * @factor, 2)
,@CO2 = ROUND(@CO2 * @factor, 2)
,@O2 = ROUND(@O2 * @factor, 2)
-- Apply error/remainder to methane
SELECT @diff = ROUND(@C2 + @C3 + @iC4 + @nC4 + @iC5 + @nC5 + @C6 + @N2 + @CO2 + @O2, 2)
SELECT @C1 = ROUND(100.0 - @diff, 2)
-- Verify total
SELECT @sumComponents = (@C1 + @C2 + @C3 + @iC4 + @nC4 + @iC5 + @nC5 + @C6 + @N2 + @CO2 + @O2)
Technorati tags: SQL