ancdec 0.3.0

Fast, precise fixed-point decimal with independent int/frac storage (u64: 19+19, u128: 38+38 digits)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
# AncDec

## Anchored Decimal

A fast, precise fixed-point decimal type for `no_std` environments with **independent** integer and fractional parts.

- **AncDec8** (u8): 2-digit integer + 2-digit fraction, 4 bytes — embedded/IoT
- **AncDec32** (u32): 9-digit integer + 9-digit fraction, 12 bytes — general purpose
- **AncDec** (u64): 19-digit integer + 19-digit fraction, 24 bytes — financial
- **AncDec128** (u128): 38-digit integer + 38-digit fraction, 40 bytes — institutional

## Why AncDec?

- **Independent storage**: Integer and fraction stored separately (not shared)
- **Exact arithmetic**: No floating-point rounding errors
- **Overflow-safe**: Wide arithmetic (u256/u512) for mul/div prevents overflow
- **Fast**: Competitive with rust_decimal across all operations
- **no_std**: Zero heap allocation, embedded-friendly
- **Zero dependencies**: No external crates required (serde, sqlx optional)
- **Safe**: All public APIs return `Result`, internal panics are unreachable by design

## Why AncDec128?

AncDec128 was introduced to handle **institutional-scale financial data** (e.g., BlackRock fund data) where integer parts regularly exceed `u64::MAX` (~1.8 x 10^19). When processing total asset values, NAV calculations, or aggregated positions, u64 integer overflow was unavoidable.

AncDec128 provides:
- **38-digit integer part** (u128::MAX ~ 3.4 x 10^38)
- **38-digit fractional part** (independent)
- **Tiered fast paths** for arithmetic: u64 -> partial product -> u128 -> u256, selecting the cheapest path automatically

## Core Structures

### AncDec8 (u8) — 4 bytes
```rust
pub struct AncDec8 {
    // Fields are pub(crate) - use new() and getters
    int: u8,        // Integer part (up to 2 digits)
    frac: u8,       // Fractional part (up to 2 digits)
    scale: u8,      // Number of decimal places (0-2)
    neg: bool,      // Sign flag
}
```

### AncDec32 (u32) — 12 bytes
```rust
pub struct AncDec32 {
    // Fields are pub(crate) - use new() and getters
    int: u32,       // Integer part (up to 9 digits)
    frac: u32,      // Fractional part (up to 9 digits)
    scale: u8,      // Number of decimal places (0-9)
    neg: bool,      // Sign flag
}
```

### AncDec (u64) — 24 bytes
```rust
pub struct AncDec {
    pub int: u64,   // Integer part (up to 19 digits)
    pub frac: u64,  // Fractional part (up to 19 digits)
    pub scale: u8,  // Number of decimal places (0-19)
    pub neg: bool,  // Sign flag
}
```

### AncDec128 (u128) — 40 bytes
```rust
pub struct AncDec128 {
    // Fields are pub(crate) - use new() and getters
    int: u128,      // Integer part (up to 38 digits)
    frac: u128,     // Fractional part (up to 38 digits)
    scale: u8,      // Number of decimal places (0-38)
    neg: bool,      // Sign flag
}
```

**Why `pub(crate)` on AncDec8, AncDec32, AncDec128?**

Their arithmetic relies on the invariant `frac < 10^scale`. Fields are `pub(crate)` to enforce validation through `new()` with `debug_assert!` at zero runtime cost in release builds.

AncDec keeps `pub` fields for backward compatibility and FFI use cases.

All structs use `#[repr(C)]` layout for FFI bindings.

## Installation
```toml
[dependencies]
ancdec = "0.3"
```

**Zero dependencies** by default. All 4 types included. Only `core` is used (no `std`, no `alloc`).

Minimal embedded build (single type only):
```toml
ancdec = { version = "0.3", default-features = false, features = ["dec8"] }
```

With serde support:
```toml
ancdec = { version = "0.3", features = ["serde"] }
```

With SQLx (PostgreSQL) support:
```toml
ancdec = { version = "0.3", features = ["sqlx"] }
```

## Usage

### Construction

```rust
use ancdec::{AncDec8, AncDec32, AncDec, AncDec128};

// From string (all types)
let a: AncDec8 = "1.23".parse()?;
let b = AncDec32::parse("123456.789")?;
let c: AncDec = "456.789".parse()?;
let d = AncDec128::parse("123456789012345678901234567890.12")?;

// Validated constructor (AncDec8, AncDec32, AncDec128)
let e = AncDec8::new(1, 23, 2, false);     // 1.23
let f = AncDec32::new(123, 456, 3, false);  // 123.456
let g = AncDec128::new(123, 456, 3, false); // 123.456

// AncDec has pub fields — direct construction
let h = AncDec { int: 123, frac: 456, scale: 3, neg: false };

// From integer primitives
let i: AncDec8 = 42u8.into();            // AncDec8: i8, u8
let j: AncDec32 = 1000i32.into();        // AncDec32: i8-i32, u8-u32
let k: AncDec = 123i64.into();           // AncDec: all 12 integer types
let l: AncDec128 = u128::MAX.into();     // AncDec128: all 12 integer types

// From float (all types, fallible)
let m = AncDec::try_from(3.14f64)?;      // TryFrom<f64>
let n = AncDec8::try_from(1.5f32)?;      // TryFrom<f32>
```

### Accessors (AncDec8, AncDec32, AncDec128)

```rust
let a = AncDec32::new(123, 456, 3, true);  // -123.456
assert_eq!(a.int(), 123);
assert_eq!(a.frac(), 456);
assert_eq!(a.scale(), 3);
assert!(a.is_neg());
```

### Arithmetic

```rust
// All 4 types support: +, -, *, /, %, +=, -=, *=, /=, %=, unary -
let a: AncDec = "12.345".parse()?;
let b: AncDec = "1.2".parse()?;

let sum = a + b;          // 13.545
let diff = a - b;         // 11.145
let product = a * b;      // 14.814
let quotient = a / b;     // 10.2875
let remainder = a % b;    // 0.345
let negated = -a;         // -12.345

// Reference variants
let c = &a + &b;
let d = a + &b;
let e = &a + b;

// Assign operators
let mut x = a;
x += b;
x -= b;
x *= b;
x /= b;
x %= b;
```

### Primitive Arithmetic

```rust
// Direct arithmetic with integer primitives (no conversion needed)
let a: AncDec8 = "1.5".parse()?;
let b = a + 2u8;             // AncDec8 + u8 → AncDec8
let c = 3i8 * a;             // i8 * AncDec8 → AncDec8

let d: AncDec32 = "100.5".parse()?;
let e = d + 50i32;           // AncDec32 + i32 → AncDec32
let f = 2u16 * d;            // u16 * AncDec32 → AncDec32

let g: AncDec = "100.0".parse()?;
let h = g / 3i64;            // AncDec / i64 → AncDec
let i = 1000u128 - g;        // u128 - AncDec → AncDec

// Supported primitive types per variant:
// AncDec8:   i8, u8
// AncDec32:  i8, i16, i32, u8, u16, u32
// AncDec:    i8-i128, isize, u8-u128, usize (all 12 types)
// AncDec128: i8-i128, isize, u8-u128, usize (all 12 types)
```

### Cross-Type Arithmetic

```rust
use ancdec::{AncDec8, AncDec32, AncDec, AncDec128};

// Smaller + larger → larger type (all 5 ops: +, -, *, /, %)
let a = AncDec8::parse("1.5")?;
let b = AncDec32::parse("2.5")?;
let c: AncDec32 = a + b;             // AncDec8 + AncDec32 → AncDec32
let d: AncDec32 = b * a;             // AncDec32 * AncDec8 → AncDec32

let e: AncDec = AncDec::parse("100.0")? + a;     // AncDec + AncDec8 → AncDec
let f: AncDec128 = AncDec128::parse("1.0")? - b;  // AncDec128 - AncDec32 → AncDec128

// 6 pairs: (8↔32), (8↔64), (8↔128), (32↔64), (32↔128), (64↔128)
// Each pair: 5 ops × 2 directions = 10 impls

// Explicit widening via From (lossless)
let g: AncDec32 = AncDec32::from(a);     // AncDec8 → AncDec32
let h: AncDec = AncDec::from(a);         // AncDec8 → AncDec
let i: AncDec128 = AncDec128::from(b);   // AncDec32 → AncDec128
```

### Math

```rust
let a: AncDec = "123.456".parse()?;

// Square root (all 4 types)
// AncDec8: 1-digit fractional, AncDec32: 8-digit, AncDec: 18-digit, AncDec128: 37-digit
let root = a.sqrt();              // 11.1111075555498660

// Power (all 4 types, supports negative exponents)
let squared = a.pow(2);           // 15241.383936
let cubed = a.pow(3);             // 1881640.295202816
let inverse = a.pow(-1);          // 1 / 123.456
let one = a.pow(0);               // 1

// Sign and query (all 4 types)
let abs_val = (-a).abs();         // 123.456
let sign = a.signum();            // 1
assert!(a.is_positive());
assert!(!a.is_negative());
assert!(!a.is_zero());

// Range (all 4 types)
let b: AncDec = "200.0".parse()?;
let min_val = a.min(b);           // 123.456
let max_val = a.max(b);           // 200.0
let clamped = a.clamp(AncDec::ZERO, AncDec::from(100i64));  // 100
```

### Rounding

```rust
use ancdec::RoundMode;

// All 4 types support all 7 rounding modes
let a: AncDec = "123.456789".parse()?;

a.round(2, RoundMode::HalfUp);     // 123.46
a.round(2, RoundMode::HalfDown);   // 123.45
a.round(2, RoundMode::HalfEven);   // 123.46
a.round(2, RoundMode::Ceil);       // 123.46
a.round(2, RoundMode::Floor);      // 123.45
a.round(2, RoundMode::Truncate);   // 123.45

// Convenience methods
a.floor();                          // 123
a.ceil();                           // 124
a.trunc();                          // 123
a.fract();                          // 0.456789
```

### Conversion

```rust
// Output conversions (all 4 types)
let a: AncDec = "123.456".parse()?;
let f: f64 = a.to_f64();           // 123.456
let i: i64 = a.to_i64();           // 123
let i128: i128 = a.to_i128();      // 123

// Display with precision (all 4 types)
let s = format!("{}", a);           // "123.456"
let s2 = format!("{:.2}", a);       // "123.45"
let s0 = format!("{:.0}", a);       // "123"
```

### Iterator Support

```rust
// Sum and Product (all 4 types, owned and reference)
let values: Vec<AncDec> = vec!["1.1", "2.2", "3.3"]
    .into_iter()
    .map(|s| s.parse().unwrap())
    .collect();

let total: AncDec = values.iter().sum();      // 6.6
let product: AncDec = values.iter().product(); // 7.986
```

## Benchmarks

### All Types vs rust_decimal

| Operation | AncDec8 | AncDec32 | AncDec | AncDec128 | rust_decimal |
|-----------|---------|----------|--------|-----------|--------------|
| add       | 2.8 ns  | 4.0 ns   | 6.3 ns | 14.5 ns   | 11.4 ns      |
| sub       | 3.2 ns  | 3.9 ns   | 6.2 ns | 14.9 ns   | 11.4 ns      |
| mul       | 4.4 ns  | 4.3 ns   | 7.4 ns | 13.5 ns   | 11.1 ns      |
| div       | 3.8 ns  | 5.5 ns   | 13.4 ns| 20.3 ns   | 20.5 ns      |
| cmp       | 1.2 ns  | 3.0 ns   | 4.4 ns | 8.0 ns    | 5.1 ns       |
| parse     | 5.7 ns  | 10.5 ns  | 10.8 ns| 14.6 ns   | 10.4 ns      |

### Speedup vs rust_decimal

| Operation | AncDec8 | AncDec32 | AncDec | AncDec128 |
|-----------|---------|----------|--------|-----------|
| add       | **4.07x** | **2.85x** | **1.81x** | 0.79x |
| sub       | **3.56x** | **2.92x** | **1.84x** | 0.77x |
| mul       | **2.52x** | **2.58x** | **1.50x** | 0.82x |
| div       | **5.39x** | **3.73x** | **1.53x** | **1.01x** |
| cmp       | **4.25x** | **1.70x** | **1.16x** | 0.64x |
| parse     | **1.82x** | ~1.0x    | ~1.0x    | 0.71x |

### AncDec128 High Precision

| Operation | AncDec128 | rust_decimal | Ratio |
|-----------|-----------|--------------|-------|
| mul       | 19.6 ns   | 18.3 ns      | 1.07x |
| div       | 54.5 ns   | 55.8 ns      | **0.98x** |
| parse     | 34.7 ns   | 30.3 ns      | 1.15x |

AncDec128 is comparable to rust_decimal while supporting **38+38 digit precision** vs rust_decimal's 28 shared digits.

*Benchmarked on Intel Core i7-10750H @ 2.60GHz, Rust 1.87.0, release mode*

## Performance Architecture

### AncDec Multiplication Fast Path

AncDec combines `int` and `frac` into a single u128 value (`int × 10^scale + frac`) before multiplication. When both combined values exceed u64 range, this requires u256 wide arithmetic (`mul_wide`). To avoid this overhead for common cases:

```
combined = int × 10^scale + frac

if combined ≤ u64::MAX for both operands:
    → cast to u64, multiply natively (u64 × u64 → u128)     ~7 ns
else:
    → mul_wide (u128 × u128 → u256) + div_wide              ~21 ns
```

**Why this is safe:** The fast path guard `a ≤ u64::MAX && b ≤ u64::MAX` guarantees the product fits in u128, because `(2⁶⁴ - 1)² = 2¹²⁸ - 2⁶⁵ + 1 < 2¹²⁸ - 1 = u128::MAX`. The operands are explicitly cast down to u64 before multiplication to make the intent unambiguous: `(a as u64 as u128) * (b as u64 as u128)`. When the combined value exceeds u64 range (e.g., `int=10^18, scale=19` → combined ≈ 10^37), the condition fails and execution falls through to `mul_wide` which handles the full u128×u128→u256 range safely.

### AncDec128 Tiered Fast Paths

AncDec128 automatically selects the fastest arithmetic path based on operand size:

**Multiplication:**
| Tier | Condition | Method | Cost |
|------|-----------|--------|------|
| 1 | Both fit in u64 combined | Native u64 x u64 | ~15 ns |
| 2 | Parts fit in u64, scale <= 19 | 4x partial product | ~25 ns |
| 3 | Both fit in u128 combined | `mul_wide` + `divmod_u256` | ~45 ns |
| 4 | Everything else | Full u256 x u256 -> u512 | ~80 ns |

**Division:**
| Tier | Condition | Method | Cost |
|------|-----------|--------|------|
| 1 | Both fit in u64 combined | Algebraic decomposition | ~25 ns |
| 2 | Both fit in u128 combined | `mul_wide` + `divmod_u256` | ~40 ns |
| 3 | Everything else | Full u512 / u256 | ~80 ns |

### Performance Cliffs

Performance drops when operands exceed a tier's threshold:

| Trigger | Effect | Typical cause |
|---------|--------|---------------|
| `scale > 19` | Skips u64 and partial product tiers | `div()` produces `scale=38` |
| `int > u64::MAX` | Skips u64 and partial product tiers | Large aggregated values |
| `int * 10^scale + frac > u128::MAX` | Falls to u256 slow path | High-scale large values |

**Common pattern:** `a.div(&b).mul(&c)` -- division produces `scale=38`, forcing subsequent multiplication into the u128 or u256 path. This is inherent to the split int/frac representation, not a bug.

## Precision Limits

| | AncDec8 (u8) | AncDec32 (u32) | AncDec (u64) | AncDec128 (u128) |
|---|---|---|---|---|
| Integer part | 2 digits | 9 digits | 19 digits | 38 digits |
| Fractional part | 2 digits | 9 digits | 19 digits | 38 digits |
| Total precision | 4 digits | 18 digits | 38 digits | 76 digits |
| sqrt() precision | 1 digit | 8 digits | 18 digits | 37 digits |
| Scale range | 0-2 | 0-9 | 0-19 | 0-38 |
| Struct size | 4 bytes | 12 bytes | 24 bytes | 40 bytes |

Fractional digits beyond the limit are truncated during parsing. Integer parts saturate at `MAX`.

## Complete API Reference

### Methods (all 4 types)

| Category | Methods |
|----------|---------|
| Construction | `parse(T)`, `new(int, frac, scale, neg)` (8/32/128), direct fields (AncDec) |
| Accessors | `int()`, `frac()`, `scale()`, `is_neg()` (8/32/128) |
| Arithmetic | `add`, `sub`, `mul`, `div`, `rem`, `checked_add`, `checked_sub`, `checked_mul` |
| Math | `sqrt()`, `pow(i32)`, `abs()`, `signum()` |
| Query | `is_zero()`, `is_positive()`, `is_negative()` |
| Range | `min()`, `max()`, `clamp()` |
| Rounding | `round(places, mode)`, `floor()`, `ceil()`, `trunc()`, `fract()` |
| Conversion | `to_f64()`, `to_i64()`, `to_i128()` |

### Operator Traits (all 4 types)

| Trait | Operators | Variants |
|-------|-----------|----------|
| `Add`, `Sub`, `Mul`, `Div`, `Rem` | `+`, `-`, `*`, `/`, `%` | value, `&ref`, cross-type, primitives |
| `AddAssign`, `SubAssign`, `MulAssign`, `DivAssign`, `RemAssign` | `+=`, `-=`, `*=`, `/=`, `%=` | |
| `Neg` | `-a` | value, `&ref` |

### Conversion Traits

| Trait | AncDec8 | AncDec32 | AncDec | AncDec128 |
|-------|---------|----------|--------|-----------|
| `From<i8>`, `From<u8>` | Yes | Yes | Yes | Yes |
| `From<i16>`, `From<u16>` | — | Yes | Yes | Yes |
| `From<i32>`, `From<u32>` | — | Yes | Yes | Yes |
| `From<i64>`, `From<u64>` | — | — | Yes | Yes |
| `From<i128>`, `From<u128>` | — | — | Yes | Yes |
| `From<isize>`, `From<usize>` | — | — | Yes | Yes |
| `TryFrom<f32>`, `TryFrom<f64>` | Yes | Yes | Yes | Yes |
| `TryFrom<&str>`, `FromStr` | Yes | Yes | Yes | Yes |

### Widening From (lossless, cfg-gated)

```
AncDec8 → AncDec32 → AncDec → AncDec128
```

| From | To AncDec32 | To AncDec | To AncDec128 |
|------|-------------|-----------|--------------|
| AncDec8 | Yes | Yes | Yes |
| AncDec32 | — | Yes | Yes |
| AncDec | — | — | Yes |

### Primitive Arithmetic

| Type | Supported primitives for `+`, `-`, `*`, `/` (both directions) |
|------|--------------------------------------------------------------|
| AncDec8 | `i8`, `u8` |
| AncDec32 | `i8`, `i16`, `i32`, `u8`, `u16`, `u32` |
| AncDec | `i8`-`i128`, `isize`, `u8`-`u128`, `usize` (12 types) |
| AncDec128 | `i8`-`i128`, `isize`, `u8`-`u128`, `usize` (12 types) |

### Cross-Type Arithmetic (cfg-gated)

All 5 operators (`+`, `-`, `*`, `/`, `%`) in both directions. Output = larger type.

| Pair | Output | Feature gate |
|------|--------|-------------|
| AncDec8 ↔ AncDec32 | AncDec32 | `dec8` + `dec32` |
| AncDec8 ↔ AncDec | AncDec | `dec8` + `dec64` |
| AncDec8 ↔ AncDec128 | AncDec128 | `dec8` + `dec128` |
| AncDec32 ↔ AncDec | AncDec | `dec32` + `dec64` |
| AncDec32 ↔ AncDec128 | AncDec128 | `dec32` + `dec128` |
| AncDec ↔ AncDec128 | AncDec128 | `dec64` + `dec128` |

### Other Traits (all 4 types)

| Trait | Notes |
|-------|-------|
| `PartialEq`, `Eq` | `0 == -0`, trailing zeros normalized |
| `PartialOrd`, `Ord` | Total ordering |
| `Hash` | Normalized (trailing zeros, `0 == -0`), usable in `HashMap`/`HashSet` |
| `Clone`, `Copy`, `Debug` | Derived |
| `Default` | Returns `ZERO` |
| `Display` | Precision support: `format!("{:.2}", a)` |
| `Sum`, `Product` | Iterator support (owned + reference) |
| `Serialize`, `Deserialize` | String-based, with `serde` feature |

### Constants

```rust
AncDec8::ZERO      AncDec32::ZERO      AncDec::ZERO       AncDec128::ZERO
AncDec8::ONE       AncDec32::ONE       AncDec::ONE        AncDec128::ONE
AncDec8::TWO       AncDec32::TWO       AncDec::TWO        AncDec128::TWO
AncDec8::TEN       AncDec32::TEN       AncDec::TEN        AncDec128::TEN
AncDec8::MAX       AncDec32::MAX       AncDec::MAX        AncDec128::MAX
```

## Features

| Feature | Dependencies | Description |
|---------|--------------|-------------|
| (default) | **None** | All 4 types, only uses `core` |
| `dec8` | — | AncDec8 only |
| `dec32` | — | AncDec32 only |
| `dec64` | — | AncDec only |
| `dec128` | — | AncDec128 only |
| `serde` | `serde` | Serialization for all enabled types |
| `sqlx` | `sqlx`, `std` | PostgreSQL NUMERIC (AncDec only) |

### Serde

All types serialize as decimal strings:
```rust
#[derive(Serialize, Deserialize)]
struct Position {
    sensor: AncDec8,
    price: AncDec,
    total_value: AncDec128,
}
// JSON: {"sensor": "1.23", "price": "123.456", "total_value": "12345678901234567890.123456"}
```

### SQLx (AncDec only)

PostgreSQL NUMERIC binary wire protocol for `AncDec` only. Implements `Type<Postgres>`, `Encode<Postgres>`, `Decode<Postgres>`.

```rust
let price: AncDec = "123.456".parse()?;
sqlx::query("INSERT INTO products (price) VALUES ($1)")
    .bind(&price)
    .execute(&pool)
    .await?;

let row: AncDec = sqlx::query_scalar("SELECT price FROM products")
    .fetch_one(&pool)
    .await?;
```

## Safety Design

### Public API - Always Safe

All public APIs return `Result` for fallible operations. Integer conversions via `From` are infallible. `checked_add`, `checked_sub`, `checked_mul` return `Option<Self>` for overflow-safe arithmetic.

### Invariant Enforcement

AncDec8, AncDec32, and AncDec128 enforce `frac < 10^scale` through:
- **`pub(crate)` fields** -- external code must use `new()` or `parse()`
- **`debug_assert!` in `new()`** -- catches violations in debug builds at zero release cost
- **All arithmetic preserves the invariant** -- internal construction is trusted

### Division by Zero

Division by zero panics (consistent with Rust's integer division). Use `is_zero()` to check before division.

## Comparison with Alternatives

| Feature | AncDec8 | AncDec32 | AncDec | AncDec128 | rust_decimal | f64 |
|---------|---------|----------|--------|-----------|--------------|-----|
| Integer precision | 2 digits | 9 digits | 19 digits | 38 digits | 28 shared | ~15 shared |
| Fractional precision | 2 digits | 9 digits | 19 digits | 38 digits | 28 shared | ~15 shared |
| Exact decimal | Yes | Yes | Yes | Yes | Yes | No |
| no_std | Yes | Yes | Yes | Yes | Feature flag | Yes |
| Zero dependencies | Yes | Yes | Yes | Yes | No | Yes |
| FFI-friendly | Yes | Yes | Yes | Yes | No | Yes |
| Struct size | 4 bytes | 12 bytes | 24 bytes | 40 bytes | 16 bytes | 8 bytes |

## Changelog

### v0.3.0

**New Types:**
- `AncDec8` (u8): 4-byte decimal for embedded/IoT (2+2 digit precision)
- `AncDec32` (u32): 12-byte decimal for general purpose (9+9 digit precision)

**New Features:**
- Feature flags (`dec8`, `dec32`, `dec64`, `dec128`) for selective compilation
- Cross-type arithmetic: `AncDec8 + AncDec32 → AncDec32` (automatic widening)
- Widening conversions via `From`: `AncDec8 → AncDec32 → AncDec → AncDec128`
- Serde support for all 4 types
- `sqrt()` for AncDec (18-digit fractional precision via Newton-Raphson on u256)
- `sqrt()` for AncDec128 (37-digit fractional precision via Newton-Raphson on u512)
- `checked_add`, `checked_sub`, `checked_mul` for all 4 types (returns `Option`)

**Breaking Changes:**
- Default features changed from none to `["dec8", "dec32", "dec64", "dec128"]`
  - Existing code compiles unchanged (all types enabled by default)
  - `default-features = false` now requires explicit feature selection
- `AncDec128` fields changed from `pub` to `pub(crate)`
  - Use `AncDec128::new(int, frac, scale, neg)` for construction
  - Use `.int()`, `.frac()`, `.scale()`, `.is_neg()` for field access
  - Enforces `frac < 10^scale` invariant via `debug_assert!`

**Bug Fixes:**
- Fixed `mul_wide` overflow in debug mode (`hl + lh` → `wrapping_add`)

**Performance:**
- AncDec mul: u64 fast path bypasses `mul_wide` when both operands fit in u64 (-65%)
- AncDec128 mul: partial product fast path for u64-sized operands (-45% for high precision)
- AncDec128 mul: u64 ultra-fast path for small operands (-10%)
- AncDec128 div: algebraic decomposition for u64 operands (-33%)
- AncDec128 div: u128 fast path avoiding full u256 arithmetic (-20%)
- AncDec128 sub: branchless `borrow * limit` pattern (-37%)
- AncDec128 add: branchless `overflow * limit` pattern (-17%)
- AncDec128 parse: two-stage u64/u128 accumulator with stage 2 gating (-18%)

### v0.2.0

- Added serde serialization/deserialization support
- Added SQLx PostgreSQL support
- Fixed mul/div overflow with u256 wide arithmetic

### v0.1.0

- Initial release with AncDec (u64-based decimal)

## License

MIT License

## Contributing

Contributions welcome! Please ensure:
- All tests pass (`cargo test`)
- Individual type tests pass (`cargo test --no-default-features --features dec8`)
- Serde tests pass (`cargo test --features serde`)
- Benchmarks don't regress (`cargo bench`)
- Code follows existing style