Skip to main content

uqa_core/
float_text.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! `PostgreSQL` floating-point text formatting shared by SQL and graph values.
8
9/// `PostgreSQL` `float8out` shortest-round-trip formatting: fixed notation while the decimal exponent is in `[-4, 15)`, scientific (`1e+15`, `1e-05`) otherwise, with `NaN` and `Infinity` spelled out.
10#[must_use]
11pub fn format_float_pg(f: f64) -> String {
12    if f.is_nan() {
13        return "NaN".into();
14    }
15    if f.is_infinite() {
16        return if f > 0.0 { "Infinity" } else { "-Infinity" }.into();
17    }
18    // `{:e}` prints the shortest round-trip mantissa in scientific
19    // form (`-3.25e-2`); re-shape it into PostgreSQL conventions.
20    let sci = format!("{f:e}");
21    let Some((mantissa, exp)) = sci.split_once('e') else {
22        return sci;
23    };
24    let Ok(exp) = exp.parse::<i32>() else {
25        return sci;
26    };
27    let negative = mantissa.starts_with('-');
28    let digits: String = mantissa.chars().filter(char::is_ascii_digit).collect();
29    let sign = if negative { "-" } else { "" };
30
31    if (-4..15).contains(&exp) {
32        if exp >= 0 {
33            let Ok(int_len) = usize::try_from(exp + 1) else {
34                return sci;
35            };
36            if digits.len() > int_len {
37                format!("{sign}{}.{}", &digits[..int_len], &digits[int_len..])
38            } else {
39                let zeros = "0".repeat(int_len - digits.len());
40                format!("{sign}{digits}{zeros}")
41            }
42        } else {
43            let Ok(zero_count) = usize::try_from(-exp - 1) else {
44                return sci;
45            };
46            let zeros = "0".repeat(zero_count);
47            format!("{sign}0.{zeros}{digits}")
48        }
49    } else {
50        let mantissa_text = if digits.len() > 1 {
51            format!("{}.{}", &digits[..1], &digits[1..])
52        } else {
53            digits
54        };
55        format!("{sign}{mantissa_text}e{exp:+03}")
56    }
57}