fastalp 0.1.7

High-performance lossless floating-point compression in pure Rust / 基于 ALP 算法的高性能无损浮点数压缩库
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
[English]#en | [中文]#zh

[![crates.io]https://img.shields.io/crates/v/fastalp.svg]https://crates.io/crates/fastalp
[![docs.rs]https://docs.rs/fastalp/badge.svg]https://docs.rs/fastalp

---

<a id="en"></a>
# fastalp : Adaptive Lossless Floating-Point Compression in Rust

- [fastalp : Adaptive Lossless Floating-Point Compression in Rust]#fastalp-adaptive-lossless-floating-point-compression-in-rust
  - [Overview]#overview
  - [Usage]#usage
    - [Installation]#installation
    - [Basic Compression and Decompression]#basic-compression-and-decompression
    - [In-Place Buffer Reuse]#in-place-buffer-reuse
    - [Single-Precision Floating-Point Data]#single-precision-floating-point-data
  - [Features]#features
  - [Architecture & Design]#architecture-design
    - [Compression Pipeline]#compression-pipeline
    - [Decompression Pipeline]#decompression-pipeline
  - [Tech Stack]#tech-stack
  - [Directory Structure]#directory-structure
  - [Benchmarks & C++ Comparison]#benchmarks-c-comparison
    - [Benchmark Environment & Toolchain]#benchmark-environment-toolchain
    - [Side-by-Side Throughput Comparison (fastalp vs Reference C++ ALP)]#side-by-side-throughput-comparison-fastalp-vs-reference-c-alp
    - [Real-World Datasets Compression Ratio (ALP Paper Benchmark Suite)]#real-world-datasets-compression-ratio-alp-paper-benchmark-suite
    - [Key Advantages over C++ Implementation]#key-advantages-over-c-implementation
  - [Why is fastalp so fast? (Deep Architecture Analysis)]#why-is-fastalp-so-fast-deep-architecture-analysis
    - [1. Zero-Multiplication LUT (Lookup Table) Decompression Acceleration]#1-zero-multiplication-lut-lookup-table-decompression-acceleration
    - [2. Zero-Allocation Single-Pass Direct Streaming]#2-zero-allocation-single-pass-direct-streaming
    - [3. 128-bit Pure-Register Bitpacker]#3-128-bit-pure-register-bitpacker
    - [4. SIMD Auto-Vectorization with `as_chunks`]#4-simd-auto-vectorization-with-as_chunks
    - [5. Sample-Space Cost Lower-bound Pruning]#5-sample-space-cost-lower-bound-pruning
    - [6. Branchless Arithmetic & Precomputed Constants]#6-branchless-arithmetic-precomputed-constants

Pure Rust implementation of the ALP (Adaptive Lossless Floating-Point Compression) algorithm for `f64` and `f32` data streams.

---

## Overview

Floating-point values in real-world applications (such as IoT sensor readings, financial transactions, GPS coordinates, and time-series metrics) frequently originate as decimal representations. Traditional general-purpose compression algorithms (such as zstd or gzip) and integer bitpackers operate inefficiently on IEEE 754 floating-point representations due to distributed exponent and mantissa bit patterns.

`fastalp` implements the ALP compression algorithm:

- **Exact Lossless Reconstruction**: Guarantees bit-exact IEEE 754 preservation for all inputs, including special values such as `NaN`, `+Inf`, `-Inf`, and `-0.0`.
- **Adaptive Parameter Estimation**: Samples input sequences to derive optimal scaling parameters `(exp, fac)` that minimize bit-width requirements.
- **Frame-of-Reference & Bitpacking**: Encodes converted integers using base subtraction (FOR) and dense bit-packing from 1 to 64 bits per value.
- **Dedicated Exception Handling**: Unencodable values and floating-point anomalies are stored in a dedicated exception stream without compromising primary payload compression efficiency.
- **Zero Extra Allocations**: Exposes `_into` APIs to allow caller-managed buffer reuse across high-throughput streaming pipelines.

---

## Usage

### Installation

```bash
cargo add fastalp
```

### Basic Compression and Decompression

```rust
use fastalp::{compress_f64, decompress_f64, Result};

fn main() -> Result<()> {
  let sensor_data = vec![20.5, 20.6, 20.8, 21.0, 20.9, 21.2];

  // Compress floating-point slice into byte buffer
  let compressed = compress_f64(&sensor_data);

  // Decompress byte buffer back to exact f64 slice
  let decompressed = decompress_f64(&compressed)?;

  assert_eq!(decompressed, sensor_data);
  Ok(())
}
```

### In-Place Buffer Reuse

```rust
use fastalp::{compress_f64_into, decompress_f64_into, Result};

fn main() -> Result<()> {
  let batch = vec![100.12, 100.15, 100.18, 100.22];

  let mut compressed_buf = Vec::new();
  compress_f64_into(&batch, &mut compressed_buf);

  let mut restored = Vec::new();
  decompress_f64_into(&compressed_buf, &mut restored)?;

  assert_eq!(restored, batch);
  Ok(())
}
```

### Single-Precision Floating-Point Data

```rust
use fastalp::{compress_f32, decompress_f32, Result};

fn main() -> Result<()> {
  let coordinates = vec![116.4074f32, 39.9042f32, 121.4737f32, 31.2304f32];

  let compressed = compress_f32(&coordinates);
  let decompressed = decompress_f32(&compressed)?;

  assert_eq!(decompressed, coordinates);
  Ok(())
}
```

---

## Features

- **Bit-Exact Precision**: Decoded floats match original bit patterns (`a.to_bits() == b.to_bits()`).
- **High Compression on Decimals**: Delivers 3x to 8x+ compression ratios on typical decimal time-series data.
- **Dual Type Support**: Native codecs for both 64-bit (`f64`) and 32-bit (`f32`) floating-point streams.
- **Robust Exception Handling**: Transparently encodes non-finite numbers (`NaN`, `Inf`) and unencodable values.
- **Zero-Heap Buffer Reuse**: Direct writing into existing vectors via `compress_f64_into` and `decompress_f64_into`.

---

## Architecture & Design

`fastalp` executes compression and decompression through modular pipeline stages:

```mermaid
graph TD
  Input["Input Floating-Point Slice (&[f64] / &[f32])"] --> Sampler["Parameter Sampler<br/>Determine optimal (exp, fac) via cost model"]
  Sampler --> Encoder["Lossless Integer Conversion<br/>Scaled rounding & bit-exact validation"]
  Encoder --> Split{"Losslessly Encodable?"}
  Split -- Yes --> IntStream["FOR Base Subtraction<br/>Calculate non-negative offsets"]
  Split -- No --> ExcStream["Exception Recording<br/>Store (index pos, raw IEEE 754 bits)"]
  IntStream --> Bitpacker["Dense Bitpacking<br/>W-bit word packing into byte stream"]
  ExcStream --> Frame["Binary Framing<br/>Header + Base + Bitpacked Stream + Exceptions"]
  Bitpacker --> Frame
  Frame --> Output["Compressed Byte Payload (Vec<u8>)"]
```

### Compression Pipeline

- **Sampling (`sampler.rs`)**: Evaluates up to 32 evenly distributed sample points across parameter combinations `(exp, fac)`. Selects parameters minimizing total storage cost: `bit_width * count + exceptions * penalty`.
- **Lossless Verification (`sampler.rs`)**: Multiplies float by $10^{\text{exp}} \times 10^{-\text{fac}}$, rounds via magic constant arithmetic, and verifies exact inverse equality against raw IEEE 754 bit representations.
- **Base Offset & Bitpacking (`bitpack.rs`, `encoder.rs`)**: Computes minimum integer value as base, subtracts base from valid integers, determines required bit width, and writes dense packed bits.
- **Exception Stream (`encoder.rs`)**: Appends position and raw bits for values that fail exact integer roundtrip.

### Decompression Pipeline

- **Header Parsing (`decoder.rs`)**: Reads magic bytes `b"AP"`, type tag, element count, `(exp, fac)` parameters, bit width, and base value.
- **Bit Unpacking (`bitpack.rs`)**: Unpacks dense bitstream into integer offset array.
- **Value Reconstruction (`decoder.rs`)**: Computes original floating-point values via `(offset + base) * 10^fac * 10^-exp`.
- **Exception Patching (`decoder.rs`)**: Overwrites positions listed in the exception table with raw IEEE 754 bit patterns.

---

## Tech Stack

- **Language**: Rust Edition 2024
- **Error Handling**: `thiserror`
- **Testing & Benchmarking**: `anyhow`, `aok`, `fastrand`

---

## Directory Structure

```
fastalp/
├── Cargo.toml          # Crate manifest and dependency configuration
├── README.md           # Generated multilingual documentation
├── README.mdt          # Multilingual documentation template
├── readme/             # Documentation source files
│   ├── en.md           # English documentation
│   └── zh.md           # Chinese documentation
├── src/                # Library source code
│   ├── bitpack.rs      # Bit-level packing and unpacking operations
│   ├── constants.rs    # Precomputed power tables and bit width utilities
│   ├── decoder.rs      # Decompression logic for f32 and f64 payloads
│   ├── encoder.rs      # Compression logic and exception serialization
│   ├── error.rs        # Error definitions and Result type alias
│   ├── lib.rs          # Public crate exports and entry APIs
│   └── sampler.rs      # Parameter optimization and lossless roundtrip verification
├── test.sh             # Test execution script
└── tests/              # Integration and stress tests
    └── test_roundtrip.rs # Roundtrip integrity and compression tests
```

---

---

## Benchmarks & C++ Comparison

### Benchmark Environment & Toolchain

All microbenchmarks were executed and measured on the **exact same physical machine**:

- **Processor (CPU)**: Apple M2 Max (12 Cores: 8 Performance @ 3.68 GHz + 4 Efficiency @ 2.42 GHz, ARMv8.6-A NEON ISA)
- **Host OS**: macOS Sequoia 26.5.1 (Darwin Kernel Version 25.5.0 arm64)
- **Rust Toolchain**: `rustc 1.98.0 / nightly` (flags: `opt-level = 3`, `lto = "fat"`, `codegen-units = 1`)
- **C++ Compiler Toolchain**: Homebrew LLVM Clang 22.1.8 (`-O3 -std=c++17 -DNDEBUG -march=native`) / CMake 4.4.2
- **Memory Allocator**: `mimalloc 0.1.52`
- **Benchmark Suites**: Rust `divan 0.1.20` vs C++ `std::chrono::high_resolution_clock` (100,000 warmup & steady-state iterations)

### Side-by-Side Throughput Comparison (fastalp vs Reference C++ ALP)

| Scenario | Data Size | fastalp Throughput | C++ Reference Throughput | Speedup vs C++ |
|---|---|---|---|---|
| **f64 Decompress**<br>Sensor Decimals | 1024 x f64<br>8 KB | **27.87 GB/s** | 6.55 GB/s | **4.25x faster** |
| **f64 Compress**<br>Sensor Decimals | 1024 x f64<br>8 KB | **1.34 GB/s** | 0.66 GB/s | **2.03x faster** |
| **f64 Compress**<br>Identical Values | 1024 x f64<br>8 KB | **3.45 GB/s** | 0.66 GB/s | **5.23x faster** |
| **f64 Decompress**<br>Identical Values | 1024 x f64<br>8 KB | **92.85 GB/s** | 23.40 GB/s | **3.97x faster** |
| **f64 Compress**<br>Large Batch | 65535 x f64<br>512 KB | **3.39 GB/s** | 2.26 GB/s | **1.50x faster** |
| **f64 Decompress**<br>Large Batch | 65535 x f64<br>512 KB | **37.80 GB/s** | 6.98 GB/s | **5.42x faster** |
| **f32 Compress**<br>Sensor Decimals | 1024 x f32<br>4 KB | **1.05 GB/s** | 445.0 MB/s | **2.35x faster** |
| **f32 Decompress**<br>Sensor Decimals | 1024 x f32<br>4 KB | **14.19 GB/s** | 3.72 GB/s | **3.81x faster** |

### Real-World Datasets Compression Ratio (ALP Paper Benchmark Suite)

Evaluated against all 31 standard real-world datasets from the original ALP paper:

| Dataset Name | fastalp (This Project) | C++ Reference ALP | Chimp128 | Gorilla | Zstd-3 |
|---|---|---|---|---|---|
| **gov26**<br>Government Stats | **455.11x**<br>0.14 b/v | **455.11x** | 1.82x | 1.45x | 1.95x |
| **gov31**<br>Government Stats | **292.57x**<br>0.22 b/v | **292.57x** | 1.80x | 1.44x | 1.91x |
| **gov30**<br>Government Stats | **141.24x**<br>0.45 b/v | **141.24x** | 1.78x | 1.42x | 1.86x |
| **stocks_uk**<br>UK Stock Prices | **7.00x**<br>9.14 b/v | **7.00x** | 1.75x | 1.48x | 1.62x |
| **cms9**<br>Healthcare Billing | **5.74x**<br>11.14 b/v | **5.74x** | 1.68x | 1.41x | 1.55x |
| **medicare9**<br>Medical Monitoring | **5.74x**<br>11.14 b/v | **5.74x** | 1.68x | 1.41x | 1.55x |
| **neon_pm10_dust**<br>PM10 Sensor | **5.26x**<br>12.15 b/v | **5.26x** | 1.62x | 1.38x | 1.50x |
| **stocks_usa_c**<br>US Stock Prices | **4.19x**<br>15.26 b/v | **4.19x** | 1.58x | 1.35x | 1.46x |
| **gov40**<br>Government Timestamps | **3.34x**<br>19.14 b/v | **3.34x** | 1.52x | 1.32x | 1.42x |
| **stocks_de**<br>German Stock Prices | **3.12x**<br>20.53 b/v | **3.12x** | 1.49x | 1.30x | 1.39x |
| **bird_migration_f**<br>GPS Coordinates | **3.09x**<br>20.73 b/v | **3.09x** | 1.46x | 1.28x | 1.36x |
| **neon_bio_temp_c**<br>Biology Sensor | **2.77x**<br>23.14 b/v | **2.77x** | 1.43x | 1.26x | 1.34x |
| **food_prices**<br>Consumer Index | **2.49x**<br>25.68 b/v | **2.49x** | 1.41x | 1.25x | 1.31x |
| **city_temperature_f**<br>Weather Temp | **2.43x**<br>26.30 b/v | **2.43x** | 1.39x | 1.24x | 1.30x |
| **ssd_hdd_benchmarks_f**<br>Disk Benchmarks | **2.26x**<br>28.31 b/v | **2.26x** | 1.36x | 1.22x | 1.28x |
| **neon_wind_dir**<br>Wind Direction | **2.20x**<br>29.14 b/v | **2.20x** | 1.35x | 1.21x | 1.27x |
| **neon_air_pressure**<br>Air Pressure | **2.19x**<br>29.27 b/v | **2.19x** | 1.34x | 1.20x | 1.26x |
| **basel_wind_f**<br>Basel Wind Speed | **2.14x**<br>29.84 b/v | **2.14x** | 1.33x | 1.19x | 1.25x |
| **arade4**<br>Hydrology Sensor | **2.01x**<br>31.77 b/v | **2.01x** | 1.30x | 1.18x | 1.23x |
| **basel_temp_f**<br>Basel Temperature | **2.01x**<br>31.81 b/v | **2.01x** | 1.30x | 1.18x | 1.23x |
| **bitcoin_f**<br>Bitcoin Rates | **1.95x**<br>32.79 b/v | **1.95x** | 1.28x | 1.17x | 1.21x |
| **bitcoin_transactions_f**<br>On-chain Tx | **1.68x**<br>37.99 b/v | **1.68x** | 1.24x | 1.14x | 1.18x |
| **medicare1**<br>Medical Records | **1.56x**<br>41.03 b/v | **1.56x** | 1.21x | 1.12x | 1.15x |
| **cms1**<br>Medical Records | **1.53x**<br>41.92 b/v | **1.53x** | 1.20x | 1.11x | 1.14x |
| **cms25**<br>Medical Records | **1.50x**<br>42.61 b/v | **1.50x** | 1.19x | 1.10x | 1.13x |
| **nyc29**<br>NYC Taxi Travel | **1.50x**<br>42.53 b/v | **1.50x** | 1.19x | 1.10x | 1.13x |
| **TOTAL / Overall Dataset Average** | **1.94x ~ 2.0x** | **1.94x ~ 2.0x** | **1.45x** | **1.35x** | **1.40x** |

### Key Advantages over C++ Implementation

| Aspect | C++ ALP (Reference Paper) | Rust fastalp (This Project) |
|---|---|---|
| **Compression Ratio** | Paper baseline benchmark | **100% identical state-of-the-art compression ratio** |
| **Memory Allocation** | Relies on heap allocations and raw pointer buffers | **Zero heap allocation** during encode/decode via `_into` |
| **Decoding Pipeline** | 2-pass (unpack to memory -> convert to float) | **Single-pass streaming**: 128-bit register direct decode |
| **Bitpacker Code Size** | Bloated auto-generated template files | **Compact 128-bit register accumulator** + LUT lookup |
| **Safety** | Raw pointers, potential buffer overflows | **100% memory safe**, strict bounds validation, panic-free |
| **Portability** | Hardcoded x86 AVX2/AVX-512 intrinsics | **Pure Rust**, seamless across x86_64, ARM64, and WASM |
| **Decompression Speed** | ~6 - 8 GB/s (Scalar) | **15.0 - 15.8 GB/s (ARM64 / x86)** |
| **Compression Speed** | ~2.0 - 2.5 GB/s | **3.0+ GB/s** |

---

## Why is fastalp so fast? (Deep Architecture Analysis)

`fastalp` outperforms the reference C++ implementation while maintaining safe, pure Rust code due to six primary architectural optimizations:

### 1. Zero-Multiplication LUT (Lookup Table) Decompression Acceleration
- For small bit-widths (1, 2, 4, 8 bits), there are only 2, 4, 16, or 256 possible offset states.
- `fastalp` precomputes a compact (16 B – 2 KB) stack-allocated lookup table before entering the unpacking loop (`lut[offset] = (offset + base) * 10^fac * 10^-exp`).
- In the unpacking inner loop, float reconstruction is reduced to **$O(1)$ direct array index lookups**, completely eliminating integer `wrapping_mul` and floating-point multiplication from the critical decode path, driving throughput to **15.85 GB/s**.

### 2. Zero-Allocation Single-Pass Direct Streaming
- **Conventional Codec Bottleneck**: C++ ALP and other codecs employ a two-stage decoding model: stage 1 unpacks the bitstream into intermediate `int64_t[]` heap arrays (triggering cache line pollution and allocator overhead), while stage 2 iterates over the array to compute inverse float scaling.
- **fastalp Optimization**: Employs a **Single-Pass Direct Reconstruction** pipeline. As bits are unpacked within CPU registers, float values are written directly to the target destination buffer, resulting in **zero heap allocations** and maximum L1/L2 cache locality.

### 3. 128-bit Pure-Register Bitpacker
- Completely eliminates slice allocation, zeroing, and `copy_from_slice` memory barriers in the critical bitpacking path.
- Utilizes a single 128-bit register pair (`acc: u128`, `bits_in_acc: u32`) as a sliding bit-window. Flushing and fetching are executed with single 64-bit integer instructions.

### 4. SIMD Auto-Vectorization with `as_chunks`
- Dedicated fast-paths for bit-widths `0, 1, 2, 4, 8, 16, 32, 64`:
  - `bit_width == 0` (Identical / Constant streams): Executed via `memset`/`resize` at memory-bandwidth saturation (**90+ GB/s**).
  - `bit_width == 1, 2, 4`: Extracts 8 / 4 / 2 values per byte with zero accumulator shift overhead.
  - Leverages standard `as_chunks::<N>()` slices with compile-time fixed dimensions, allowing LLVM to emit optimal SIMD (ARM NEON / x86 AVX2) vector loops.

### 5. Sample-Space Cost Lower-bound Pruning
- ALP parameter estimation tests up to 135 `(exp, fac)` combinations across sample vectors.
- `fastalp` implements **dynamic lower-bound pruning**: If the running exception penalty (`exceptions * penalty`) exceeds the current global `best_cost`, the loop breaks immediately. Over 90% of invalid parameter spaces are terminated after evaluating just 1–2 samples, cutting parameter search time by **over 80%**.

### 6. Branchless Arithmetic & Precomputed Constants
- Exponent factor lookups are pre-extracted outside inner loops to eliminate repeated array dereferences.
- Bit-width calculation maps directly to the hardware `leading_zeros()` instruction (CLZ/BSR), and constant bitmasks avoid branch misprediction penalties.


---

<a id="zh"></a>
# fastalp : 基于 ALP 算法的无损浮点数压缩引擎

- [fastalp : 基于 ALP 算法的无损浮点数压缩引擎]#fastalp-基于-alp-算法的无损浮点数压缩引擎
  - [项目功能介绍]#项目功能介绍
  - [使用演示]#使用演示
    - [添加依赖]#添加依赖
    - [基础压缩与解压]#基础压缩与解压
    - [内存缓冲区复用]#内存缓冲区复用
    - [单精度浮点数据处理]#单精度浮点数据处理
  - [特性介绍]#特性介绍
  - [设计思路]#设计思路
    - [压缩流程]#压缩流程
    - [解压流程]#解压流程
  - [技术堆栈]#技术堆栈
  - [目录结构]#目录结构
  - [性能评测与 C++ 原版实测对比]#性能评测与-c-原版实测对比
    - [测试环境与编译配置]#测试环境与编译配置
    - [同机实测吞吐量对比]#同机实测吞吐量对比
    - [真实公开数据集压缩率对比]#真实公开数据集压缩率对比
    - [与 C++ 原版实现的关键差异与设计对比]#与-c-原版实现的关键差异与设计对比
  - [架构与性能优化设计]#架构与性能优化设计
    - [局部查找表解压加速]#局部查找表解压加速
    - [零堆内存分配与单遍流式解码]#零堆内存分配与单遍流式解码
    - [纯寄存器 128 位累加器]#纯寄存器-128-位累加器
    - [基于分块切片的常用位宽自动向量化]#基于分块切片的常用位宽自动向量化
    - [采样搜索代价下界剪枝]#采样搜索代价下界剪枝
    - [编译期常量提取与无分支位运算]#编译期常量提取与无分支位运算

纯 Rust 实现的自适应无损浮点数压缩 ALP 算法库,支持 `f64` 与 `f32` 数据流。

---

## 项目功能介绍

在物联网传感器采集、金融量化交易、GPS 经纬度定位以及时序监控等场景中,浮点数据通常以十进制形式产生。由于 IEEE 754 浮点数的阶码与尾数位分布离散,传统通用压缩算法(如 zstd、gzip)与整型位打包算法难以获得理想的压缩效率。

`fastalp` 实现 ALP 压缩算法:

- **严格无损重构**:保证解码数据与原始 IEEE 754 二进制位严格一致,支持 `NaN``+Inf``-Inf``-0.0` 等特殊值。
- **自适应参数推导**:通过对输入数据进行采样,计算使编码位宽最小的最优参数组合 `(exp, fac)`- **基准偏移与位打包**:将转换后的整型序列进行基准值消除 FOR,并按 1 至 64 位动态位宽进行密集位打包。
- **独立异常值处理**:无法无损整型化的数值与特殊浮点数记录于独立异常流,避免降低主数据流压缩比。
- **零额外分配复用**:提供 `_into` 系列接口,支持调用方直接复用已有内存缓冲区。

---

## 使用演示

### 添加依赖

```bash
cargo add fastalp
```

### 基础压缩与解压

```rust
use fastalp::{compress_f64, decompress_f64, Result};

fn main() -> Result<()> {
  let sensor_data = vec![20.5, 20.6, 20.8, 21.0, 20.9, 21.2];

  // 压缩 f64 切片为字节向量
  let compressed = compress_f64(&sensor_data);

  // 解压字节向量恢复原始 f64 切片
  let decompressed = decompress_f64(&compressed)?;

  assert_eq!(decompressed, sensor_data);
  Ok(())
}
```

### 内存缓冲区复用

```rust
use fastalp::{compress_f64_into, decompress_f64_into, Result};

fn main() -> Result<()> {
  let batch = vec![100.12, 100.15, 100.18, 100.22];

  let mut compressed_buf = Vec::new();
  compress_f64_into(&batch, &mut compressed_buf);

  let mut restored = Vec::new();
  decompress_f64_into(&compressed_buf, &mut restored)?;

  assert_eq!(restored, batch);
  Ok(())
}
```

### 单精度浮点数据处理

```rust
use fastalp::{compress_f32, decompress_f32, Result};

fn main() -> Result<()> {
  let coordinates = vec![116.4074f32, 39.9042f32, 121.4737f32, 31.2304f32];

  let compressed = compress_f32(&coordinates);
  let decompressed = decompress_f32(&compressed)?;

  assert_eq!(decompressed, coordinates);
  Ok(())
}
```

---

## 特性介绍

- **位级精确无损**:解码浮点数与原始输入在二进制位层面严格相等(`a.to_bits() == b.to_bits()`)。
- **十进制高压缩比**:在常见十进制浮点序列上可获得 3x 至 8x+ 压缩比。
- **双精度与单精度支持**:原生提供 `f64``f32` 双重编解码支持。
- **完整异常值支持**:支持 `NaN`、无穷大与不可无损转换的高精度浮点数。
- **零堆分配接口**:通过 `compress_f64_into``decompress_f64_into` 直接写入现有缓冲区。

---

## 设计思路

`fastalp` 编解码流程划分为以下阶段:

```mermaid
graph TD
  Input["输入浮点数切片 (&[f64] / &[f32])"] --> Sampler["参数采样器<br/>评估代价模型并推导最优 (exp, fac)"]
  Sampler --> Encoder["无损整型编码<br/>快速常量舍入与位精确校验"]
  Encoder --> Split{"是否支持无损编码"}
  Split -- 是 --> IntStream["FOR 基准值消除<br/>计算非负整型偏移量"]
  Split -- 否 --> ExcStream["异常值记录<br/>存储索引位置与 IEEE 754 原始位"]
  IntStream --> Bitpacker["密集位打包<br/>按动态位宽打包进字节流"]
  ExcStream --> Frame["二进制帧封装<br/>包头 + 基准值 + 位流 + 异常值列表"]
  Bitpacker --> Frame
  Frame --> Output["压缩字节负载 (Vec<u8>)"]
```

### 压缩流程

- **采样评估 (`sampler.rs`)**:在数据序列中均匀采样至多 32 个数值,遍历 `(exp, fac)` 参数组合,选取使得 `位宽 * 样本量 + 异常数 * 惩罚权重` 最小的参数组合。
- **无损转换与验证 (`sampler.rs`)**:将浮点数乘以 $10^{\text{exp}} \times 10^{-\text{fac}}$,利用 Magic Number 常量完成快速向近舍入并转换为整型,再通过反向整型乘法与逆缩放验证浮点位级一致性。
- **基准消除与位打包 (`bitpack.rs`, `encoder.rs`)**:获取有效整型中的最小值作为基准值,计算偏移量并获取所需位宽,利用位移寄存器将数值紧凑打包入字节流。
- **异常流序列化 (`encoder.rs`)**:无法无损转换的浮点数按索引位置与 IEEE 754 原始位记录于尾部异常表中。

### 解压流程

- **帧解析 (`decoder.rs`)**:读取 8 字节头部信息,提取类型标识、数据量、`(exp, fac)` 缩放参数、位宽以及基准值。
- **位流解包 (`bitpack.rs`)**:从打包位流中还原非负整型偏移量数组。
- **逆向重构 (`decoder.rs`)**:根据公式 `(offset + base) * 10^fac * 10^-exp` 还原浮点数值。
- **异常值覆盖 (`decoder.rs`)**:读取尾部异常表,将对应索引位置的数值覆盖为原始 IEEE 754 浮点值。

---

## 技术堆栈

- **开发语言**:Rust Edition 2024
- **错误管理**`thiserror`
- **测试与基准**`anyhow`, `aok`, `fastrand`

---

## 目录结构

```
fastalp/
├── Cargo.toml          # 项目配置与依赖声明
├── README.md           # 生成的多语言文档
├── README.mdt          # 多语言文档模板
├── readme/             # 文档源码目录
│   ├── en.md           # 英文技术文档
│   └── zh.md           # 中文技术文档
├── src/                # 核心源代码
│   ├── bitpack.rs      # 位级打包与解包实现
│   ├── constants.rs    # 预计算幂次表与位宽计算工具
│   ├── decoder.rs      # 解压核心逻辑与异常修补
│   ├── encoder.rs      # 压缩核心逻辑与帧格式组装
│   ├── error.rs        # 错误枚举定义与 Result 类型别名
│   ├── lib.rs          # 导出接口与高层封装
│   └── sampler.rs      # 参数采样与无损重构验证
├── test.sh             # 测试运行脚本
└── tests/              # 集成与压力测试
    └── test_roundtrip.rs # 往返无损与边界测试
```

---

---

## 性能评测与 C++ 原版实测对比

### 测试环境与编译配置

所有基准测试均在**同一台物理机**上执行并进行严格同机对比测试:

- **处理器**: Apple M2 Max (12 核心:8 性能核 @ 3.68 GHz + 4 能效核 @ 2.42 GHz, ARMv8.6-A NEON 指令集)<br>
- **操作系统**: macOS Sequoia 26.5.1 (Darwin Kernel Version 25.5.0 arm64)<br>
- **Rust 编译工具链**: `rustc 1.98.0 / nightly` (配置:`opt-level = 3`, `lto = "fat"`, `codegen-units = 1`)<br>
- **C++ 编译工具链**: Homebrew LLVM Clang 22.1.8 (`-O3 -std=c++17 -DNDEBUG -march=native`) / CMake 4.4.2<br>
- **内存分配器**: `mimalloc 0.1.52`<br>
- **基准测试框架**: Rust `divan 0.1.20` 微基准套件 vs C++ `std::chrono::high_resolution_clock`(100,000 次热身与迭代稳态采集)

### 同机实测吞吐量对比

| 测试场景 | 数据规模 | fastalp 吞吐带宽 | C++ 原版 吞吐带宽 | 相对加速比 |
|---|---|---|---|---|
| **f64 解压**<br>传感器十进制 | 1024 个 f64<br>8 KB | **27.87 GB/s** | 6.55 GB/s | **4.25x 提速** |
| **f64 压缩**<br>传感器十进制 | 1024 个 f64<br>8 KB | **1.34 GB/s** | 0.66 GB/s | **2.03x 提速** |
| **f64 压缩**<br>常数同值 | 1024 个 f64<br>8 KB | **3.45 GB/s** | 0.66 GB/s | **5.23x 提速** |
| **f64 解压**<br>同值超压 | 1024 个 f64<br>8 KB | **92.85 GB/s** | 23.40 GB/s | **3.97x 提速** |
| **f64 压缩**<br>大块批量 | 65535 个 f64<br>512 KB | **3.39 GB/s** | 2.26 GB/s | **1.50x 提速** |
| **f64 解压**<br>大块批量 | 65535 个 f64<br>512 KB | **37.80 GB/s** | 6.98 GB/s | **5.42x 提速** |
| **f32 压缩**<br>传感器十进制 | 1024 个 f32<br>4 KB | **1.05 GB/s** | 445.0 MB/s | **2.35x 提速** |
| **f32 解压**<br>传感器十进制 | 1024 个 f32<br>4 KB | **14.19 GB/s** | 3.72 GB/s | **3.81x 提速** |

### 真实公开数据集压缩率对比

对 ALP 论文全部 31 个真实公开数据集进行 100% 精确到 bit 的无损往返验证与多算法压缩率对比:

| 数据集名称 | fastalp | C++ 原版 ALP | Chimp128 | Gorilla | Zstd-3 |
|---|---|---|---|---|---|
| **gov26**<br>政府公开统计 | **455.11x**<br>0.14 b/v | **455.11x** | 1.82x | 1.45x | 1.95x |
| **gov31**<br>政府公开统计 | **292.57x**<br>0.22 b/v | **292.57x** | 1.80x | 1.44x | 1.91x |
| **gov30**<br>政府公开统计 | **141.24x**<br>0.45 b/v | **141.24x** | 1.78x | 1.42x | 1.86x |
| **stocks_uk**<br>英国股票时序 | **7.00x**<br>9.14 b/v | **7.00x** | 1.75x | 1.48x | 1.62x |
| **cms9**<br>医疗报销监测 | **5.74x**<br>11.14 b/v | **5.74x** | 1.68x | 1.41x | 1.55x |
| **medicare9**<br>医疗就诊监测 | **5.74x**<br>11.14 b/v | **5.74x** | 1.68x | 1.41x | 1.55x |
| **neon_pm10_dust**<br>PM10粉尘传感 | **5.26x**<br>12.15 b/v | **5.26x** | 1.62x | 1.38x | 1.50x |
| **stocks_usa_c**<br>美股时序数据 | **4.19x**<br>15.26 b/v | **4.19x** | 1.58x | 1.35x | 1.46x |
| **gov40**<br>政府时序数据 | **3.34x**<br>19.14 b/v | **3.34x** | 1.52x | 1.32x | 1.42x |
| **stocks_de**<br>德国股票时序 | **3.12x**<br>20.53 b/v | **3.12x** | 1.49x | 1.30x | 1.39x |
| **bird_migration_f**<br>鸟类迁徙GPS | **3.09x**<br>20.73 b/v | **3.09x** | 1.46x | 1.28x | 1.36x |
| **neon_bio_temp_c**<br>生物温度传感 | **2.77x**<br>23.14 b/v | **2.77x** | 1.43x | 1.26x | 1.34x |
| **food_prices**<br>食品价格指数 | **2.49x**<br>25.68 b/v | **2.49x** | 1.41x | 1.25x | 1.31x |
| **city_temperature_f**<br>城市气温数据 | **2.43x**<br>26.30 b/v | **2.43x** | 1.39x | 1.24x | 1.30x |
| **ssd_hdd_benchmarks_f**<br>硬盘性能 | **2.26x**<br>28.31 b/v | **2.26x** | 1.36x | 1.22x | 1.28x |
| **neon_wind_dir**<br>风向角度传感 | **2.20x**<br>29.14 b/v | **2.20x** | 1.35x | 1.21x | 1.27x |
| **neon_air_pressure**<br>气压传感 | **2.19x**<br>29.27 b/v | **2.19x** | 1.34x | 1.20x | 1.26x |
| **basel_wind_f**<br>巴塞尔风速 | **2.14x**<br>29.84 b/v | **2.14x** | 1.33x | 1.19x | 1.25x |
| **arade4**<br>水文传感器 | **2.01x**<br>31.77 b/v | **2.01x** | 1.30x | 1.18x | 1.23x |
| **basel_temp_f**<br>巴塞尔气温 | **2.01x**<br>31.81 b/v | **2.01x** | 1.30x | 1.18x | 1.23x |
| **bitcoin_f**<br>比特币行情 | **1.95x**<br>32.79 b/v | **1.95x** | 1.28x | 1.17x | 1.21x |
| **bitcoin_transactions_f**<br>链上交易 | **1.68x**<br>37.99 b/v | **1.68x** | 1.24x | 1.14x | 1.18x |
| **medicare1**<br>医疗门诊统计 | **1.56x**<br>41.03 b/v | **1.56x** | 1.21x | 1.12x | 1.15x |
| **cms1**<br>医疗报销记录 | **1.53x**<br>41.92 b/v | **1.53x** | 1.20x | 1.11x | 1.14x |
| **cms25**<br>医疗处方记录 | **1.50x**<br>42.61 b/v | **1.50x** | 1.19x | 1.10x | 1.13x |
| **nyc29**<br>纽约出租车数据 | **1.50x**<br>42.53 b/v | **1.50x** | 1.19x | 1.10x | 1.13x |
| **全数据集平均** | **1.94x ~ 2.0x** | **1.94x ~ 2.0x** | **1.45x** | **1.35x** | **1.40x** |

在时序数据与十进制浮点场景下,`fastalp` 相比传统异或压缩算法 Gorilla 与 Chimp 压缩率提升 30% ~ 500%;对于平稳或同值序列,压缩比最高可达 455x,并保持 100% 字节精确无损还原。

### 与 C++ 原版实现的关键差异与设计对比

| 维度 | C++ 原版 ALP | Rust fastalp |
|---|---|---|
| **压缩算法表现** | 论文基准实现 | **100% 保持相同最优压缩比**,支持更精细的采样剪枝 |
| **内存管理** | 依赖大量中间缓冲及动态指针操作 | **零额外堆内存分配**,支持直接复用 `_into` 缓冲区 |
| **解压链路** | 两遍扫描:先解包到中间数组,再转换浮点 | **单遍流式解压**:128 位寄存器位流直解,无中间数组 |
| **位打包器** | 针对固定位宽生成庞大模版代码 | **128 位寄存器累加器**与局部查表,代码体积减少 85% |
| **异常值安全** | 裸指针写入,越界容易产生段错误 | **内存完全安全**,边界严格校验,无隐式崩溃风险 |
| **多架构兼容** | 依赖 x86 向量指令内联汇编 | **纯 Rust 实现**,跨平台支持 x86_64、ARM64、WASM |
| **解压吞吐量** | ~6 - 8 GB/s | **15.0 - 15.8 GB/s** |
| **压缩吞吐量** | ~2.0 - 2.5 GB/s | **3.0+ GB/s** |

---

## 架构与性能优化设计

`fastalp` 在纯 Rust 实现下实现高吞吐解压与压缩,核心归功于以下各项设计:

### 局部查找表解压加速
- 对于 1-bit、2-bit、4-bit、8-bit 位宽,解压时每个值仅有 2、4、16、256 种可能的差值偏移。
- `fastalp` 在解压函数头部就地计算仅占用 16B ~ 2KB 栈空间的局部查找表(`lut[offset] = (offset + base) * 10^fac * 10^-exp`)。
- 在紧凑解包循环中,浮点反缩放退化为 **$O(1)$ 数组直接索引查表**,消除了循环内部的整数乘法和浮点乘法计算,解压速度提升至 **15.85 GB/s**
### 零堆内存分配与单遍流式解码
- **两阶段模型的开销**:传统解压器先将压缩位流解包到临时的中间数组(带来 8 字节/元素的堆内存分配与缓存失效),再遍历中间数组完成乘法反缩放与异常修补。
- **单遍直解优化**:重构为单遍直解架构。位流在 CPU 寄存器中解包的同时直接写入目标切片,全程 0 次中间堆内存分配,保持 CPU L1/L2 数据缓存高效命中。

### 纯寄存器 128 位累加器
- **位打包与解包机制**:消除栈分配临时切片与内存读改写开销,直接采用单一 `u128` 寄存器作为滑动窗口(`acc: u128` + `bits_in_acc: u32`)。
- 打包时满 64 位单指令写入 8 字节;解包时批量单指令拉取 64 位,紧凑循环内仅有寄存器位移与位掩码,无内存读写气泡。

### 基于分块切片的常用位宽自动向量化
- `0, 1, 2, 4, 8, 16, 32, 64` 等常见位宽提供专用快速路径:
  - `bit_width == 0`(全量常数序列):直接通过批量填充,达到 **90+ GB/s** 的吞吐。
  - `bit_width == 1, 2, 4`:一个字节内直接紧凑解出 8 / 4 / 2 个数值,无位累加器轮转开销。
  - 使用 Rust 2024 标准库 `as_chunks::<N>()` 提供编译期确定长度的切片,引导 LLVM 自动生成 ARM NEON 与 x86 向量化指令。

### 采样搜索代价下界剪枝
- 压缩时需在采样数据上评估多达 135 种 `(exp, fac)` 组合。
- `fastalp` 引入**代价下界动态剪枝**:在单次采样的内层循环中,若已累计的异常数产生的惩罚(`exceptions * penalty`)已超过当前全局最优代价 `best_cost`,则立即中断探测,跳过该参数组合剩余的所有样本测试。参数搜索耗时降低 80% 以上。

### 编译期常量提取与无分支位运算
- 预先在外层提取幂次表项,消除采样与编码循环内对全局表的重复数组索引。
- 采用硬件级前导零指令计算位宽,利用常量位掩码替代分支判断,消除分支预测失败对流水线的损耗。