Skip to content

Commit 2ea3bf9

Browse files
Merge pull request #7 from iShape-Rust/feature/new_ratio_api
Feature/new ratio api
2 parents e184afa + 1a52624 commit 2ea3bf9

17 files changed

Lines changed: 1200 additions & 83 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: ci-${{ github.workflow }}-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
env:
16+
CARGO_TERM_COLOR: always
17+
18+
jobs:
19+
quality:
20+
name: Quality and tests
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- name: Install Rust components
26+
run: rustup component add rustfmt clippy
27+
28+
- name: Check formatting
29+
run: cargo fmt --all -- --check
30+
31+
- name: Run Clippy
32+
run: cargo clippy --lib --all-features -- -D warnings
33+
34+
- name: Run tests
35+
run: cargo test --all-targets --all-features
36+
37+
- name: Run release tests
38+
run: cargo test --release --all-targets --all-features
39+
40+
- name: Run documentation tests
41+
run: cargo test --doc --all-features
42+
43+
- name: Build documentation
44+
env:
45+
RUSTDOCFLAGS: -D warnings
46+
run: cargo doc --no-deps --all-features
47+
48+
feature-matrix:
49+
name: Features / ${{ matrix.name }}
50+
runs-on: ubuntu-latest
51+
strategy:
52+
fail-fast: false
53+
matrix:
54+
include:
55+
- name: no-default
56+
args: --no-default-features
57+
- name: core
58+
args: --no-default-features --features core
59+
- name: glam
60+
args: --no-default-features --features glam
61+
- name: serde
62+
args: --no-default-features --features serde
63+
- name: all
64+
args: --all-features
65+
steps:
66+
- uses: actions/checkout@v4
67+
68+
- name: Check feature configuration
69+
run: cargo check ${{ matrix.args }}
70+
71+
msrv:
72+
name: MSRV / Rust 1.85
73+
runs-on: ubuntu-latest
74+
steps:
75+
- uses: actions/checkout@v4
76+
77+
- name: Install MSRV toolchain
78+
run: rustup toolchain install 1.85.0 --profile minimal
79+
80+
- name: Check all features on MSRV
81+
run: cargo +1.85.0 check --all-features
82+
83+
distribution:
84+
name: Wasm and package
85+
runs-on: ubuntu-latest
86+
steps:
87+
- uses: actions/checkout@v4
88+
89+
- name: Install wasm target
90+
run: rustup target add wasm32-unknown-unknown
91+
92+
- name: Check wasm target
93+
run: cargo check --target wasm32-unknown-unknown --all-features
94+
95+
- name: Verify package
96+
run: cargo package

‎Cargo.toml‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ name = "i_float"
33
version = "4.0.0"
44
authors = ["Nail Sharipov <nailxsharipov@gmail.com>"]
55
edition = "2024"
6+
rust-version = "1.85"
67
description = "This fixed float math library provides an efficient and deterministic solution for arithmetic and geometric operations."
78
license = "MIT"
89
repository = "https://github.com/iShape-Rust/iFloat"
@@ -11,12 +12,11 @@ categories = ["no-std", "mathematics"]
1112

1213
[features]
1314
default = ["core"]
14-
core = ["float_pt"]
15-
float_pt = []
16-
glam = ["dep:glam"]
17-
serde = ["dep:serde"]
15+
core = []
16+
glam = ["dep:glam", "core"]
17+
serde = ["dep:serde", "core"]
1818

1919
[dependencies]
2020
serde = { version = "^1.0", default-features = false, features = ["derive"], optional = true }
2121
glam = { optional = true, version = ">=0.27" }
22-
libm = "^0.2"
22+
libm = "^0.2"

‎README.md‎

Lines changed: 104 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,140 @@
11
# iFloat
22

3-
This fixed float math library provides an efficient and deterministic solution for arithmetic and geometric operations.
3+
`i_float` provides numeric primitives for deterministic 2D geometry:
44

5-
## Features
6-
7-
- Fixed-point arithmetic using FixNumber for deterministic calculations
5+
- generic integer points, vectors, and rectangles;
6+
- wide intermediate integer arithmetic;
7+
- conversion between floating-point and integer coordinate spaces;
8+
- fixed-scale unit ratios for interpolation;
9+
- basic triangle predicates;
10+
- optional `serde` and `glam` integration.
811

9-
- 2D fixed-point vector operations with FixVec
12+
The crate is `no_std` and supports `i16`, `i32`, and `i64` coordinate types.
1013

11-
- Trigonometric functions using fixed-point angles
14+
## Installation
1215

13-
- Angle conversion and manipulation utilities in FixAngle
16+
```toml
17+
[dependencies]
18+
i_float = "4.0"
19+
```
1420

21+
The default `core` feature exposes the complete numeric and geometry API.
1522

16-
## Installation
23+
## Integer geometry
1724

25+
`IntPoint<T>` stores coordinates in `T`. Subtracting two points produces an
26+
`IntVector<T>` whose components use the associated wide integer type: `i32`
27+
coordinates produce an `i64` vector, while `i64` coordinates produce an
28+
`i128` vector.
1829

1930
```rust
20-
use i_float::fix_float::FixFloat;
21-
use i_float::fix_vec::FixVec;
22-
```
31+
use i_float::int::point::IntPoint;
32+
use i_float::triangle::Triangle;
2333

34+
let a = IntPoint::new(0_i32, 0);
35+
let b = IntPoint::new(10, 0);
36+
let c = IntPoint::new(0, 10);
2437

25-
## How It Works
38+
let ab = b - a;
39+
assert_eq!(ab.x, 10_i64);
40+
assert_eq!(ab.y, 0_i64);
2641

27-
The \`**FixFloat**\` struct uses fixed-point arithmetic to perform calculations with a high degree of precision and determinism. It supports numbers in the range 2^21 - 1 to -2^21 + 1 with a precision of 1/1024, and is most suitable for the range 1,000,000 to -1,000,000 with a precision of 0.01.
42+
assert_eq!(Triangle::area_two(a, b, c), 100_i64);
43+
assert!(!Triangle::is_clockwise(a, b, c));
44+
```
2845

29-
Fixed-point numbers are represented using a fixed number of bits for the fractional part. In this implementation, the number of bits representing the fractional part of the fixed-point number is 10, which allows for a precision of 1/1024 or approximately 0.001.
46+
### Coordinate range
3047

31-
Here are some examples of fixed-point number representation:
48+
Integer geometry intentionally uses a coordinate range narrower than the full
49+
range of the underlying integer. Although point differences are widened, dot
50+
products, cross products, and squared lengths multiply wide values without
51+
widening them again.
3252

33-
- 1 / 1024 ≈ 0.001 (represented as 1)
34-
- 256 / 1024 = 0.25 (represented as 256)
35-
- 1024 / 1024 = 1 (represented as 1024)
36-
- (1024 + 512) / 1024 = 1.5 (represented as 1536)
37-
- (2048 + 256) / 1024 = 2.25 (represented as 2304)
53+
A conservative common bound for all point and vector operations is:
3854

39-
By using the \`**FixFloat**\` struct, you can perform arithmetic operations using i64 values while maintaining the precision of floating-point numbers, ensuring deterministic behavior across different platforms and devices.
55+
```text
56+
-2^(I::BITS - 2) < coordinate < 2^(I::BITS - 2)
57+
```
4058

59+
For example, `i32` coordinates should stay strictly between
60+
`-1_073_741_824` and `1_073_741_824`. This leaves enough headroom for the
61+
difference of two points and for the sum or difference of two products in
62+
`I::Wide`. Operations use normal integer arithmetic and do not perform runtime
63+
range checks.
4164

42-
## Usage
65+
This bound is deliberately universal and conservative. An algorithm may use a
66+
wider range when it proves that its particular intermediate expressions still
67+
fit. Conversely, an `IntVector` constructed directly from arbitrary wide values
68+
is not covered by the point-coordinate bound.
4369

44-
### FixFloat
70+
Floating-point input should normally be mapped with `FloatPointAdapter`. For an
71+
explicit general-purpose safety margin, use `with_coordinate_bits` with at most
72+
`I::BITS - 3`; algorithms with stronger range analysis may select a larger bit
73+
budget.
4574

46-
The \`**FixFloat**\` struct represents a fixed-point number using a \`**i64**\` as the underlying storage, allowing deterministic arithmetic operations. Use \`**FixFloat**\` for calculations instead of \`**i32**\` or \`**i64**\` when deterministic behavior is required. \`**FixFloat**\` provides a way to perform arithmetic operations with \`**i64**\` values while maintaining the precision of floating-point numbers.
75+
## Floating-point adapter
76+
77+
`FloatPointAdapter` maps a bounded floating-point coordinate space onto an
78+
integer grid. The same adapter converts results back into the original space.
4779

4880
```rust
49-
let a = FixFloat::new_number(1);
50-
let b = FixFloat::new_number(2);
51-
let c = a + b;
52-
```
81+
use i_float::adapter::FloatPointAdapter;
82+
use i_float::float::rect::FloatRect;
83+
use i_float::int::point::IntPoint;
5384

54-
### FixVec
85+
let bounds = FloatRect::new(-10.0_f64, 10.0, -5.0, 5.0);
86+
let adapter = FloatPointAdapter::<[f64; 2], i32>::new(bounds);
5587

56-
The \`**FixVec**\` struct represents a 2D fixed-point vector, providing various utility methods and operators for vector operations. Use \`**FixVec**\` for 2D geometric calculations when deterministic behavior is required.
88+
let source = [2.5, -1.25];
89+
let point: IntPoint<i32> = adapter.try_float_to_int(&source).unwrap();
90+
let restored = adapter.try_int_to_float(&point).unwrap();
5791

58-
```rust
59-
let a = FixVec::new_number(1, 1);
60-
let b = FixVec::new_number(1, -1);
61-
let c = a + b;
92+
let tolerance = adapter.inv_scale();
93+
assert!((restored[0] - source[0]).abs() <= tolerance);
94+
assert!((restored[1] - source[1]).abs() <= tolerance);
6295
```
6396

64-
### FixAngle
65-
The \`**FixAngle**\` class provides various utility methods for working with fixed-point angles, including trigonometric functions and angle conversion.
97+
Use `with_coordinate_bits` when an algorithm has an explicit coordinate-bit
98+
budget. The value controls only the converted coordinate magnitude; it does not
99+
prove that every later arithmetic expression is safe. Use `try_with_scale` or
100+
`try_with_scale_and_coordinate_bits` when a caller supplies the scale and
101+
invalid or unsafe scales must be rejected.
102+
103+
## Fixed-scale ratios
66104

105+
`UnitRatio<I>` represents a value in the inclusive range `0..=1`. Its stored
106+
integer value uses `FixedScale<I>::DENOMINATOR` as one. Scaling rounds midpoint
107+
values away from zero.
67108

68109
```rust
69-
let fix_angle = FixAngle::new_from_radians_f64(angle);
70-
let fix_sin = fix_angle.sin();
71-
let i64_sin = fix_sin.double();
110+
use i_float::int::number::unit_ratio::UnitRatio;
111+
use i_float::int::point::IntPoint;
112+
113+
let quarter = UnitRatio::<i32>::from_int(1, 4);
114+
let half = UnitRatio::<i32>::half();
115+
116+
assert_eq!(quarter.scale(10), 3);
117+
assert_eq!(quarter.scale(-10), -3);
118+
assert_eq!(quarter.mid(half), UnitRatio::from_int(3, 8));
119+
120+
let point = IntPoint::new(100, -40);
121+
assert_eq!(quarter.scale_point(point), IntPoint::new(25, -10));
72122
```
73123

124+
Constructors currently expect valid input. In particular, `new` expects a
125+
stored value between zero and `DENOMINATOR`, `from_float` expects a finite value
126+
between zero and one, and `from_int` expects `0 <= numerator <= denominator`.
127+
These preconditions are checked by debug assertions.
128+
129+
## Features
130+
131+
| Feature | Default | Description |
132+
| --- | --- | --- |
133+
| `core` | yes | Integer and floating-point primitives, adapters, and triangle predicates |
134+
| `serde` | no | Enables serialization for supported geometry types and also enables `core` |
135+
| `glam` | no | Adds conversions for `glam::Vec2`, `DVec2`, and `IVec2` and also enables `core` |
136+
74137

75138
## License
139+
140+
Licensed under the MIT License. See the `LICENSE` file.

0 commit comments

Comments
 (0)