Browse Source

Increase precision for percent changes

Most notably with small percent changes, add or subtract, the error
introduced by truncation on double to integer keeps adding up.

Round raw values calculated from percentages to reduce error introduced
by truncation from double to integer.
Daniel Rodríguez 5 years ago
parent
commit
ea837111b4
1 changed files with 10 additions and 6 deletions
  1. 10
    6
      src/light.c

+ 10
- 6
src/light.c View File

164
 
164
 
165
 static bool _light_percent_to_raw(light_device_target_t *target, double inpercent, uint64_t *outraw)
165
 static bool _light_percent_to_raw(light_device_target_t *target, double inpercent, uint64_t *outraw)
166
 {
166
 {
167
-    uint64_t max_value = 0;
167
+    uint64_t max_value = 0, target_value;
168
+
168
     if(!target->get_max_value(target, &max_value))
169
     if(!target->get_max_value(target, &max_value))
169
     {
170
     {
170
         LIGHT_ERR("couldn't read from target");
171
         LIGHT_ERR("couldn't read from target");
171
         return false;
172
         return false;
172
     }
173
     }
173
 
174
 
174
-    double max_value_d = (double)max_value;
175
-    double target_value_d = max_value_d * (light_percent_clamp(inpercent) / 100.0);
176
-    uint64_t target_value = LIGHT_CLAMP((uint64_t)target_value_d, 0, max_value);
177
-    *outraw = target_value;
178
-    
175
+    inpercent = light_percent_clamp(inpercent);
176
+
177
+    /* Round to the nearest integer by adding 0.5 after division.
178
+       Reduces error introduced by truncation after multiple increments or
179
+       decrements. */
180
+    target_value = max_value * inpercent / 100.0 + 0.5;
181
+    *outraw = LIGHT_CLAMP(target_value, 0, max_value);
182
+
179
     return true;
183
     return true;
180
 }
184
 }
181
 
185