Insufficient Precision or Accuracy of a Real Number
Description
Insufficient Precision or Accuracy of a Real Number occurs when a product processes real numbers using an implementation where the representation does not preserve required accuracy and precision in the fractional part, leading to incorrect results. When security decisions or calculations depend on highly precise numbers—such as financial transactions or pricing—small variations can be exploited. Multiple storage methods exist including fixed-point, floating-point, and ratio-based representations, each with accuracy limitations. Issues arise when fractions cannot be represented in fixed digits, repeating decimals occur, or transcendental numbers appear. Rounding errors cause computer results to diverge from mathematically accurate outcomes.
Risk
Insufficient precision has severe implications. Financial calculation errors leading to monetary loss. Security bypass through calculation manipulation. Buffer overflows from miscalculated bounds. Application crashes from undefined results. Infinite loops from precision errors. Safety-critical system failures. Exploitable rounding errors. High likelihood when precise calculations drive security decisions.
Solution
Adopt more accurate real number representations during architecture and design phase. Use ratios of BigInts for extremely fine precision. Implement Unum reals for enhanced accuracy. Evaluate memory and CPU tradeoffs as alternatives to hardware floating-point typically shift calculations to slower software implementations. Use fixed-point arithmetic where precision requirements are well-defined during implementation phase.
Common Consequences
| Impact | Details |
|---|---|
| Availability | Scope: Availability Undefined results often cause crashes, halts, or infinite loops during overflow conditions. |
| Integrity | Scope: Integrity Miscalculated values produce incorrect answers with security implications. |
| Confidentiality | Scope: Confidentiality, Integrity, Access Control Can trigger buffer overflows enabling arbitrary code execution through bounds miscalculation. |
Example Code
Vulnerable Code
// Vulnerable: Floating-point precision issues
// VULNERABLE: Muller's Recurrence with standard floats
fn vulnerable_recurrence(y: f64, z: f64) -> f64 {
// This formula should converge to 5.0
// But floating-point errors cause it to diverge
108.0 - ((815.0 - 1500.0 / z) / y)
}
fn vulnerable_muller_sequence() {
let mut y = 4.0_f64;
let mut z = 4.25_f64;
// VULNERABLE: Precision loss causes wrong convergence
for i in 0..30 {
let next = vulnerable_recurrence(y, z);
println!("Iteration {}: {}", i, next);
z = y;
y = next;
// Expected: converges to 5.0
// Actual: diverges to 100.0 due to precision errors
}
}
# Vulnerable: Python floating-point issues
# VULNERABLE: Financial calculation with float
def vulnerable_calculate_total(prices):
# VULNERABLE: Floating-point accumulation errors
total = 0.0
for price in prices:
total += price
return total
# Example: 0.1 + 0.2 != 0.3 in floating-point
# >>> 0.1 + 0.2
# 0.30000000000000004
# VULNERABLE: Currency conversion
def vulnerable_convert_currency(amount, rate):
# VULNERABLE: Precision loss in conversion
return amount * rate
# Small errors compound over many transactions
# VULNERABLE: Interest calculation
def vulnerable_compound_interest(principal, rate, years, compounds_per_year):
# VULNERABLE: Exponential amplifies precision errors
return principal * (1 + rate / compounds_per_year) ** (compounds_per_year * years)
# VULNERABLE: Division that should be exact
def vulnerable_split_bill(total, num_people):
# VULNERABLE: May not divide evenly
per_person = total / num_people
calculated_total = per_person * num_people
# calculated_total may not equal total due to precision
return per_person
# VULNERABLE: Comparison with floating-point
def vulnerable_balance_check(balance, withdrawal):
# VULNERABLE: Direct floating-point comparison
remaining = balance - withdrawal
if remaining == 0.0: # May never be exactly zero
return "Account empty"
elif remaining < 0:
return "Insufficient funds"
else:
return "OK"
// Vulnerable: C floating-point issues
#include <stdio.h>
#include <math.h>
// VULNERABLE: Buffer size calculation with float
void vulnerable_buffer_allocation(float data_size, float factor) {
// VULNERABLE: Precision loss in size calculation
int buffer_size = (int)(data_size * factor);
// If factor = 1.1 and data_size = 100
// Expected: 110, but could be 109 due to truncation
char* buffer = malloc(buffer_size);
// Potential buffer too small for actual data
}
// VULNERABLE: Loop with floating-point counter
void vulnerable_float_loop() {
// VULNERABLE: May not terminate as expected
for (float f = 0.0f; f != 1.0f; f += 0.1f) {
printf("%f\n", f);
// 0.1 cannot be represented exactly in binary
// Loop may overshoot 1.0 and never terminate
}
}
// VULNERABLE: Security check with float comparison
int vulnerable_access_check(float user_level, float required_level) {
// VULNERABLE: Direct equality comparison
if (user_level == required_level) {
return 1; // Grant access
}
// May fail even when values should be equal
return 0;
}
// VULNERABLE: Coordinate calculation for security boundary
int vulnerable_point_in_boundary(float x, float y, float boundary) {
// VULNERABLE: Precision errors at boundary edges
float distance = sqrt(x*x + y*y);
if (distance < boundary) {
return 1; // Inside
}
// Points very close to boundary may be misclassified
return 0;
}
Fixed Code
// Fixed: Using precise rational arithmetic
use num_rational::BigRational;
use num_bigint::BigInt;
// FIXED: Muller's Recurrence with arbitrary precision
fn safe_recurrence(y: BigRational, z: BigRational) -> BigRational {
// FIXED: BigRational provides exact arithmetic
let c108 = BigRational::from_integer(BigInt::from(108));
let c815 = BigRational::from_integer(BigInt::from(815));
let c1500 = BigRational::from_integer(BigInt::from(1500));
c108 - ((c815 - c1500 / z) / y)
}
fn safe_muller_sequence() {
let mut y = BigRational::new(BigInt::from(4), BigInt::from(1));
let mut z = BigRational::new(BigInt::from(17), BigInt::from(4)); // 4.25
// FIXED: Converges correctly to 5.0
for i in 0..30 {
let next = safe_recurrence(y.clone(), z.clone());
println!("Iteration {}: {}", i, next);
z = y;
y = next;
// Correctly converges to 5
}
}
# Fixed: Python with precise decimal/fraction handling
from decimal import Decimal, ROUND_HALF_UP, getcontext
from fractions import Fraction
# FIXED: Set precision for financial calculations
getcontext().prec = 28
# FIXED: Financial calculation with Decimal
def safe_calculate_total(prices):
# FIXED: Use Decimal for exact decimal arithmetic
total = Decimal('0')
for price in prices:
total += Decimal(str(price))
return total
# FIXED: Currency conversion with controlled rounding
def safe_convert_currency(amount, rate, decimal_places=2):
# FIXED: Explicit precision and rounding
amount_dec = Decimal(str(amount))
rate_dec = Decimal(str(rate))
result = amount_dec * rate_dec
# Round to specified decimal places
return result.quantize(Decimal(10) ** -decimal_places, rounding=ROUND_HALF_UP)
# FIXED: Interest calculation with Decimal
def safe_compound_interest(principal, rate, years, compounds_per_year):
# FIXED: Decimal arithmetic for financial precision
p = Decimal(str(principal))
r = Decimal(str(rate))
n = Decimal(str(compounds_per_year))
t = Decimal(str(years))
result = p * (1 + r / n) ** (n * t)
return result.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
# FIXED: Exact division with Fraction
def safe_split_bill(total, num_people):
# FIXED: Use Fraction for exact division
total_frac = Fraction(total).limit_denominator(100)
per_person = total_frac / num_people
# For display, convert to cents
cents = int(per_person * 100)
return cents / 100
# FIXED: Comparison with tolerance
EPSILON = Decimal('0.0001')
def safe_balance_check(balance, withdrawal):
# FIXED: Compare with tolerance
remaining = Decimal(str(balance)) - Decimal(str(withdrawal))
if abs(remaining) < EPSILON:
return "Account empty"
elif remaining < 0:
return "Insufficient funds"
else:
return "OK"
# FIXED: Validate precision requirements
def safe_calculation_with_validation(a, b, required_precision):
"""Perform calculation with precision validation."""
# FIXED: Set appropriate precision
getcontext().prec = required_precision + 10 # Extra margin
a_dec = Decimal(str(a))
b_dec = Decimal(str(b))
result = a_dec * b_dec
# FIXED: Verify precision maintained
if len(str(result).replace('.', '').lstrip('0')) > required_precision:
# Round to required precision
result = result.quantize(Decimal(10) ** -(required_precision - 1))
return result
// Fixed: C with precise arithmetic
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
// FIXED: Use integer cents instead of float dollars
typedef int64_t cents_t;
// FIXED: Buffer size calculation with integer arithmetic
void safe_buffer_allocation(size_t data_size, int factor_percent) {
// FIXED: Use integer percentage (110% = 110)
size_t buffer_size = (data_size * factor_percent + 99) / 100;
// +99 ensures rounding up
char* buffer = malloc(buffer_size);
// Buffer size is exact
}
// FIXED: Loop with integer counter
void safe_integer_loop(int iterations) {
// FIXED: Use integer counter
for (int i = 0; i < iterations; i++) {
// Perform operations
float progress = (float)i / iterations; // Only for display
printf("Progress: %.1f%%\n", progress * 100);
}
}
// FIXED: Floating-point comparison with epsilon
#define EPSILON 1e-9
int safe_float_equal(double a, double b) {
// FIXED: Compare with tolerance
return fabs(a - b) < EPSILON;
}
int safe_float_less_than(double a, double b) {
// FIXED: Account for precision
return (a - b) < -EPSILON;
}
// FIXED: Security check with tolerance
int safe_access_check(double user_level, double required_level) {
// FIXED: Use epsilon comparison
if (fabs(user_level - required_level) < EPSILON) {
return 1; // Grant access
}
if (user_level > required_level + EPSILON) {
return 1; // Also grant if above
}
return 0;
}
// FIXED: Boundary check with safety margin
int safe_point_in_boundary(double x, double y, double boundary) {
// FIXED: Include epsilon for boundary uncertainty
double distance = sqrt(x*x + y*y);
// Points within epsilon of boundary are treated as uncertain
if (distance < boundary - EPSILON) {
return 1; // Definitely inside
} else if (distance > boundary + EPSILON) {
return 0; // Definitely outside
} else {
return -1; // On boundary - handle specially
}
}
// FIXED: Fixed-point arithmetic for financial
typedef struct {
int64_t value; // Value in smallest unit (cents)
int decimals; // Number of decimal places
} fixed_point_t;
fixed_point_t fp_multiply(fixed_point_t a, fixed_point_t b) {
// FIXED: Exact multiplication with known precision
fixed_point_t result;
result.value = (a.value * b.value) / pow(10, b.decimals);
result.decimals = a.decimals;
return result;
}
CVE Examples
- CVE-1991-0001: Patriot missile system clock drift due to floating-point accumulation causing tracking failure (28 casualties in Dhahran).
- CVE-1996-0001: Ariane 5 rocket explosion due to floating-point to integer conversion overflow.
Related CWEs
- CWE-682: Incorrect Calculation (parent)
- CWE-190: Integer Overflow or Wraparound (peer)
- CWE-119: Improper Restriction of Operations within Memory Buffer Bounds (can follow)
- CWE-834: Excessive Iteration (can follow)
- CWE-189: Numeric Errors (category)
References
- MITRE Corporation. "CWE-1339: Insufficient Precision or Accuracy of a Real Number." https://cwe.mitre.org/data/definitions/1339.html
- Goldberg, David. "What Every Computer Scientist Should Know About Floating-Point Arithmetic"
- IEEE 754. "Standard for Floating-Point Arithmetic"