What you are doing is correct.
The problem is that 2.1
does not exist as a 32-bit float value (nor as a 64-bit float, aka. double, for that matter).
The 2.1
double value actually has the value 2.100000000000000088817841970012523233890533447265625.
That is the nearest double value to the mathematical value 2.1, so that's what you get when you write 2.1 as a double.
When that value is stored into a (32-bit) float, the nearest float value is picked.
The two closest representable float values are:
- 2.099999904632568359375
- 2.1000001430511474609375
The former has the smaller distance to the double "2.1" (~0.000000095 vs ~0.000000143), so that's the float used to represent the double value.
Even if you could write floats directly, the smaller number is also closer to the mathematical number 2.1, so it's still the one you get.
What likely happens is that at the other end, the MODBUS server reads out your float, converts it back to a double, which it can without loss. That double is not the double for "2.1", and therefore it's treated as being smaller than 2.1. When they then do .toFixed(3)
(or whatever they do to get three decimals), that's what you end up with.
If you had picked the larger of the floats, then it too would different from 2.1, but at least it has the advantage that it rounds to 2.100 with three fractional digits.
If you know that, maybe you can choose a float value which rounds as you want, instead of one that is closer to the actual double:
/// Returns a float value (as a double) that approximates the double.
double roundableFloat(double doubleValue, int fractionalDigits) {
var target = doubleValue.toStringAsFixed(fractionalDigits);
var buffer = Float32List(1);
buffer[0] = doubleValue;
var rounded = buffer[0];
var result = rounded.toStringAsFixed(fractionalDigits);
if (result != target) {
// Assume same endianness for floats and integers.
// Not always true on ARM, so more cleverness might be needed.
buffer.buffer.asUint32List()[0] += rounded < doubleValue ? 1 : -1;
rounded = buffer[0];
}
return rounded;
}
Somewhat cumbersome and inefficient, but if you can't fix the server, it might help.