//|
/// Mathematical Derivation of Maximum Decimal Digits for Integer Types
///
/// Given:
/// - I is an integer type
/// - n is the bit width of type I  
/// - I_Max is the maximum value of type I
/// - pow(2,n) - 1 == I_Max (for unsigned types)
/// - pow(2,n-1) - 1 == I_Max (for signed types, considering sign bit)
///
/// Theorem: 
/// log₁₀(I_Max) represents the maximum count of decimal digits that can be 
/// represented by type I (excluding sign for negative numbers).
///
/// Since I_Max < pow(2,n), we have:
/// log₁₀(I_Max) < log₁₀(pow(2,n)) = n * log₁₀(2)
///
/// Using a bounding approach and the fact that we need integer digit counts:
/// The upper bound of decimal digits for type I is ⌊n * log₁₀(2)⌋ + 1
/// where the +1 accounts for potential rounding and sign representation.
///
/// Note: log₁₀(2) ≈ 0.30103, so n * log₁₀(2) gives us the theoretical maximum.

///|
/// Practical Constants for Maximum Decimal Digits
/// These constants represent the exact maximum decimal digits needed
/// to represent any value of the corresponding integer type.
///
/// https://en.cppreference.com/w/cpp/types/numeric_limits/digits10.html
///

///|
/// Maximum decimal digits for UInt8/Byte: 2^8 - 1 = 255 (3 digits)
/// Theoretical: ⌊8 * 0.30103⌋ + 1 = ⌊2.408⌋ + 1 = 3 ✓
const Byte_Digits10 = 3

///|
/// Maximum decimal digits for UInt16: 2^16 - 1 = 65535 (5 digits)  
/// Theoretical: ⌊16 * 0.30103⌋ + 1 = ⌊4.816⌋ + 1 = 5 ✓
const UInt16_Digits10 = 5

///|
/// Maximum decimal digits for Int16: -2^15 to 2^15 - 1 (-32768 to 32767)
/// Minimum value -32768 requires 6 digits including sign
/// Theoretical: ⌊15 * 0.30103⌋ + 2 = ⌊4.515⌋ + 2 = 6 ✓ (extra +1 for sign)
const Int16_Digits10 = 6

///|
/// Maximum decimal digits for UInt32/UInt: 2^32 - 1 = 4294967295 (10 digits)
/// Theoretical: ⌊32 * 0.30103⌋ + 1 = ⌊9.633⌋ + 1 = 10 ✓
const UInt_Digits10 = 10

///|
/// Maximum decimal digits for Int32/Int: -2^31 to 2^31 - 1 (-2147483648 to 2147483647)
/// Minimum value -2147483648 requires 11 digits including sign
/// Theoretical: ⌊31 * 0.30103⌋ + 2 = ⌊9.332⌋ + 2 = 11 ✓ (extra +1 for sign)
const Int_Digits10 = 11

///|
/// Maximum decimal digits for UInt64: 2^64 - 1 = 18446744073709551615 (20 digits)
/// Theoretical: ⌊64 * 0.30103⌋ + 1 = ⌊19.266⌋ + 1 = 20 ✓
const UInt64_Digits10 = 20

///|
/// Maximum decimal digits for Int64: -2^63 to 2^63 - 1
/// Minimum value -9223372036854775808 requires 20 digits including sign
/// Theoretical: ⌊63 * 0.30103⌋ + 2 = ⌊18.965⌋ + 2 = 20 ✓ (extra +1 for sign)
const Int64_Digits10 = 20

///|
/// Verification Tests
/// These tests verify that our theoretical calculations match practical reality
test "decimal digits constants verification" {
  // Byte: 2^8 - 1 = 255
  inspect((255).to_string().length(), content="3")
  inspect(Byte_Digits10, content="3")

  // UInt16: 2^16 - 1 = 65535
  inspect((65535).to_string().length(), content="5")
  inspect(UInt16_Digits10, content="5")

  // Int16: -2^15 = -32768
  inspect((-32768).to_string().length(), content="6")
  inspect(Int16_Digits10, content="6")

  // UInt: 2^32 - 1 = 4294967295
  inspect(4294967295U.to_string().length(), content="10")
  inspect(UInt_Digits10, content="10")

  // Int: -2^31 = -2147483648
  inspect((-2147483648).to_string().length(), content="11")
  inspect(Int_Digits10, content="11")
}

///|
/// Mathematical Proof Validation
/// This test demonstrates the mathematical relationship between bit width and decimal digits
test "mathematical proof validation" {
  // Verify that our constants follow the theoretical upper bound formula
  // For unsigned types: digits ≤ ⌊n * log₁₀(2)⌋ + 1
  // For signed types: digits ≤ ⌊(n-1) * log₁₀(2)⌋ + 2

  let log10_2 = @math.log10(2) // log₁₀(2) ≈ 0.30103

  // UInt8: ⌊8 * 0.30103⌋ + 1 = 3
  let byte_theoretical = (8.0 * log10_2).to_int() + 1
  inspect(byte_theoretical, content="3")
  inspect(Byte_Digits10 <= byte_theoretical, content="true")

  // UInt16: ⌊16 * 0.30103⌋ + 1 = 5  
  let uint16_theoretical = (16.0 * log10_2).to_int() + 1
  inspect(uint16_theoretical, content="5")
  inspect(UInt16_Digits10 <= uint16_theoretical, content="true")

  // Int16: ⌊15 * 0.30103⌋ + 2 = 6
  let int16_theoretical = (15.0 * log10_2).to_int() + 2
  inspect(int16_theoretical, content="6")
  inspect(Int16_Digits10 <= int16_theoretical, content="true")
}

///|
fn init {
  // Prevent unused constant warnings
  ignore([
    Byte_Digits10,
    UInt16_Digits10,
    Int16_Digits10,
    UInt_Digits10,
    Int_Digits10,
    UInt64_Digits10,
    Int64_Digits10,
    Byte_Digits,
    UInt16_Digits,
    Int16_Digits,
    UInt_Digits,
    Int_Digits,
    Int64_Digits,
    UInt64_Digits,
  ])
}