Files
2026-01-25 16:22:30 -07:00

214 lines
6.3 KiB
C++

#ifndef SALVIUM_H
#define SALVIUM_H
#include <cstdint>
#include <stdexcept>
#include <string>
#include <sstream>
#include <iomanip>
// Fixed-point decimal type for Salvium atomic units
// Stores values as uint64_t with 8 decimal places (dusty precision)
// Arithmetic operations fail loudly on overflow/underflow
class Salvium {
private:
static constexpr uint64_t ATOMIC_UNIT = 100000000ULL; // 10^8
static constexpr int DECIMAL_PLACES = 8;
uint64_t atomic_units; // value in dusties
// Helper to detect overflow in multiplication
static bool will_overflow_multiply(uint64_t a, uint64_t b) {
if (a == 0 || b == 0) return false;
return a > UINT64_MAX / b;
}
// Helper to detect overflow in addition
static bool will_overflow_add(uint64_t a, uint64_t b) {
return a > UINT64_MAX - b;
}
public:
// Construct from atomic units (dusties)
explicit Salvium(uint64_t atomic = 0) : atomic_units(atomic) {}
// Construct from decimal string (e.g., "1.5", "100", "0.00000001")
// Parses directly to atomic units without floating-point
static Salvium from_string(const std::string& s) {
if (s.empty()) {
throw std::invalid_argument("Empty string");
}
size_t decimal_pos = s.find('.');
std::string whole_str = (decimal_pos == std::string::npos) ? s : s.substr(0, decimal_pos);
std::string frac_str = (decimal_pos == std::string::npos) ? "" : s.substr(decimal_pos + 1);
// Validate characters
for (char c : whole_str) {
if (c < '0' || c > '9') {
throw std::invalid_argument("Invalid character in whole part");
}
}
for (char c : frac_str) {
if (c < '0' || c > '9') {
throw std::invalid_argument("Invalid character in fractional part");
}
}
// Check fractional precision
if (frac_str.length() > DECIMAL_PLACES) {
throw std::invalid_argument("Too many decimal places (max 8)");
}
// Pad fractional part to 8 digits
while (frac_str.length() < DECIMAL_PLACES) {
frac_str += '0';
}
// Parse parts
uint64_t whole = 0;
if (!whole_str.empty()) {
for (char c : whole_str) {
uint64_t digit = c - '0';
if (will_overflow_multiply(whole, 10)) {
throw std::overflow_error("Value exceeds maximum");
}
whole *= 10;
if (will_overflow_add(whole, digit)) {
throw std::overflow_error("Value exceeds maximum");
}
whole += digit;
}
}
uint64_t frac = 0;
for (char c : frac_str) {
frac = frac * 10 + (c - '0');
}
// Combine: whole * ATOMIC_UNIT + frac
if (will_overflow_multiply(whole, ATOMIC_UNIT)) {
throw std::overflow_error("Value exceeds maximum");
}
uint64_t atomic = whole * ATOMIC_UNIT;
if (will_overflow_add(atomic, frac)) {
throw std::overflow_error("Value exceeds maximum");
}
return Salvium(atomic + frac);
}
// Get value in atomic units (dusties)
uint64_t to_atomic() const {
return atomic_units;
}
// Get value as display string (Salvium)
std::string to_salvium_string() const {
std::ostringstream oss;
oss << std::fixed << std::setprecision(DECIMAL_PLACES);
uint64_t whole = atomic_units / ATOMIC_UNIT;
uint64_t fractional = atomic_units % ATOMIC_UNIT;
oss << whole << "." << std::setfill('0') << std::setw(DECIMAL_PLACES) << fractional;
std::string result = oss.str();
// Strip trailing zeros after decimal point
size_t decimal_pos = result.find('.');
if (decimal_pos != std::string::npos) {
result.erase(result.find_last_not_of('0') + 1);
if (result.back() == '.') {
result.pop_back();
}
}
return result;
}
// Arithmetic operators
Salvium operator+(const Salvium& other) const {
if (will_overflow_add(atomic_units, other.atomic_units)) {
throw std::overflow_error("Addition overflow");
}
return Salvium(atomic_units + other.atomic_units);
}
Salvium operator-(const Salvium& other) const {
if (atomic_units < other.atomic_units) {
throw std::underflow_error("Subtraction underflow");
}
return Salvium(atomic_units - other.atomic_units);
}
Salvium operator*(uint64_t scalar) const {
if (will_overflow_multiply(atomic_units, scalar)) {
throw std::overflow_error("Multiplication overflow");
}
return Salvium(atomic_units * scalar);
}
Salvium operator/(uint64_t scalar) const {
if (scalar == 0) {
throw std::invalid_argument("Division by zero");
}
return Salvium(atomic_units / scalar);
}
// In-place operators
Salvium& operator+=(const Salvium& other) {
*this = *this + other;
return *this;
}
Salvium& operator-=(const Salvium& other) {
*this = *this - other;
return *this;
}
Salvium& operator*=(uint64_t scalar) {
*this = *this * scalar;
return *this;
}
Salvium& operator/=(uint64_t scalar) {
*this = *this / scalar;
return *this;
}
// Comparison operators
bool operator==(const Salvium& other) const {
return atomic_units == other.atomic_units;
}
bool operator!=(const Salvium& other) const {
return atomic_units != other.atomic_units;
}
bool operator<(const Salvium& other) const {
return atomic_units < other.atomic_units;
}
bool operator<=(const Salvium& other) const {
return atomic_units <= other.atomic_units;
}
bool operator>(const Salvium& other) const {
return atomic_units > other.atomic_units;
}
bool operator>=(const Salvium& other) const {
return atomic_units >= other.atomic_units;
}
// Zero check
bool is_zero() const {
return atomic_units == 0;
}
};
#endif // SALVIUM_H