Mobile Development 10 min read

HarmonyOS Float Precision Pitfalls: Choosing the Right Type for Sensor Data

This article explores floating-point precision issues in HarmonyOS development, demonstrating how float's 7-digit limit corrupts sensor data, why double increases memory 30% and fails in Native calls, and why BigDecimal kills real-time performance, concluding with a scenario-based selection strategy and validation mechanism.

51CTO HarmonyOS Developer Community
51CTO HarmonyOS Developer Community
51CTO HarmonyOS Developer Community
HarmonyOS Float Precision Pitfalls: Choosing the Right Type for Sensor Data

Problem: Sensor Data Jitter Caused by Float Precision Loss

While developing a sensor data collection feature on a real device, the author observed chart curves vibrating excessively. The algorithm logic was correct, but logged float values differed from expectations by 0.3–0.7 in decimal places. The root cause was not HarmonyOS but a misunderstanding of float and double precision.

Float's 7‑Significant‑Digit Limit

The accelerometer module reads raw data from SensorEvent.values[], which is a float[]. Assuming 32‑bit float precision was sufficient, the author found that when the device tilt approached 90°, the calculated inclination error spiked above 5°. Printing each float value revealed the issue:

float value = sensorEvent.values[0]; // Raw value: 1.23456789
Log.d("DEBUG", "Float: " + value); // Output: 1.234568

Only 6–7 significant digits were retained; the rest were rounded off. This is an inherent limitation of single‑precision floats: they can precisely represent at most 7 significant digits. When multiple floating‑point operations are chained, rounding errors amplify exponentially.

I thought: it's just an attitude angle, two decimal places are enough. Result: when multiple float operations stack, rounding errors amplify exponentially.

Double Is Not a Silver Bullet: Memory and Native Traps

Switching all variables to double increased memory usage by 30% , causing noticeable launch lag on low‑end devices. Worse, double does not solve precision loss when crossing the Java/Native boundary.

In a C++ interface defined as:

// C++ interface definition
void process_accel(float* data, int len);

Calling it from Java with a double[] array:

// Java layer call
double[] input = new double[3];
// ... fill data
nativeLib.process_accel(input, 3); // Automatically converted to float, double loses effect

The double values are implicitly narrowed to float, wasting the extra precision. HarmonyOS Native interfaces (especially those annotated with @CalledByNative) default to float parameters; even if you pass double, the lower layer truncates it.

I thought using double would guarantee precision, but I got trapped instead. Finally realized: precision is not decided by type alone, but by the entire data‑flow chain.

Why BigDecimal Is Discouraged in HarmonyOS

Using BigDecimal for high precision caused severe performance degradation: every calculation creates a new object, generating enough GC pressure to stall the main thread. Moreover, HarmonyOS's JVM lacks native fast conversion between BigDecimal and float / double; manual string parsing is required, which is extremely slow.

// ❌ Not recommended
BigDecimal a = new BigDecimal("1.23456789");
BigDecimal b = new BigDecimal("0.12345678");
BigDecimal result = a.add(b); // Creates new object each time, huge overhead
I used to think: as long as precision is high, speed doesn't matter. Testing proved: in real‑time scenarios (sensors, animation interpolation), performance is the primary productivity.

Scenario‑Based Floating‑Point Selection Strategy

✅ Scenario 1: Raw Sensor Data Processing → Use float

Raw data is already float; no conversion needed.

Precision requirement within ±0.01°.

Advantages: small memory, fast, fully compatible with SensorManager.

✅ Scenario 2: Complex Math (Filtering, Integration) → Use double Temporarily

Use double only during intermediate computation.

After calculation, immediately cast back to float for output or transmission.

Example:

double temp = Math.sin(angle) * 0.5;
float finalValue = (float) temp; // Retain precision, avoid propagation

✅ Scenario 3: High‑Precision Storage (Finance, Metrology) → Use String + BigDecimal (Sparingly)

Only for final display or persistence.

Never use in real‑time calculation pipelines.

Encapsulate in a utility class to avoid frequent object creation.

Engineering Guard: Float Validation Mechanism

The author added a FloatValidator class to monitor precision loss on critical paths:

public class FloatValidator {
    public static boolean isWithinTolerance(double expected, double actual, double tolerance) {
        return Math.abs(expected - actual) < tolerance;
    }

    public static void logIfUnstable(float value, String tag) {
        if (Math.abs(value - Math.round(value * 1e6) / 1e6) > 1e-5) {
            Log.w(tag, "⚠️ Floating‑point value may be distorted: " + value);
        }
    }
}

Insert checks at key function entry points:

FloatValidator.logIfUnstable(accX, "SensorData");
This caught two hidden precision issues before release, preventing user complaints.

Beginner Pitfall Checklist

Don't perform float‑intensive calculations in @Entry pages — blocks the UI thread.

Don't use float for timestamp accumulation — even millisecond errors accumulate into minute‑level drift.

In @Component , if a @Prop field involves floats, ensure the parent passes float ; otherwise it becomes doublefloat conversion, losing precision.

For cross‑module communication (e.g., EventBus), prefer float to avoid serialization bloat from double.

Final Insight: Precision Is a Pipeline Problem, Not a Type Problem

The author used to believe picking the right type solved everything. Now the understanding is:

Floating‑point precision is fundamentally the "fidelity capability" of the entire data pipeline.

From sensor sampling → Java processing → Native computation → graphics rendering → user perception, any single stage that downgrades the type nullifies all prior effort.

So stop asking "float or double?" Instead ask yourself: At which step will this value be discarded? Who is responsible for preserving precision?
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

memory optimizationHarmonyOSprecisionBigDecimalsensor datafloatdoubleNative interface
51CTO HarmonyOS Developer Community
Written by

51CTO HarmonyOS Developer Community

The HarmonyOS Developer Community is a learning-oriented community for developers to learn, communicate, ask questions, and share.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.