i_float 4.1.0

This fixed float math library provides an efficient and deterministic solution for arithmetic and geometric operations.
Documentation
# iFloat

`i_float` provides numeric primitives for deterministic 2D geometry:

- generic integer points, vectors, and rectangles;
- wide intermediate integer arithmetic;
- conversion between floating-point and integer coordinate spaces;
- fixed-scale unit ratios for interpolation;
- basic triangle predicates;
- optional `serde` and `glam` integration.

The crate is `no_std` and supports `i16`, `i32`, and `i64` coordinate types.

## Installation

```toml
[dependencies]
i_float = "4.0"
```

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

## Integer geometry

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

```rust
use i_float::int::point::IntPoint;
use i_float::triangle::Triangle;

let a = IntPoint::new(0_i32, 0);
let b = IntPoint::new(10, 0);
let c = IntPoint::new(0, 10);

let ab = b - a;
assert_eq!(ab.x, 10_i64);
assert_eq!(ab.y, 0_i64);

assert_eq!(Triangle::area_two(a, b, c), 100_i64);
assert!(!Triangle::is_clockwise(a, b, c));
```

### Coordinate range

Integer geometry intentionally uses a coordinate range narrower than the full
range of the underlying integer. Although point differences are widened, dot
products, cross products, and squared lengths multiply wide values without
widening them again.

A conservative common bound for all point and vector operations is:

```text
-2^(I::BITS - 2) < coordinate < 2^(I::BITS - 2)
```

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

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

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

## Floating-point adapter

`FloatPointAdapter` maps a bounded floating-point coordinate space onto an
integer grid. The same adapter converts results back into the original space.

```rust
use i_float::adapter::FloatPointAdapter;
use i_float::float::rect::FloatRect;
use i_float::int::point::IntPoint;

let bounds = FloatRect::new(-10.0_f64, 10.0, -5.0, 5.0);
let adapter = FloatPointAdapter::<[f64; 2], i32>::new(bounds);

let source = [2.5, -1.25];
let point: IntPoint<i32> = adapter.try_float_to_int(&source).unwrap();
let restored = adapter.try_int_to_float(&point).unwrap();

let tolerance = adapter.inv_scale();
assert!((restored[0] - source[0]).abs() <= tolerance);
assert!((restored[1] - source[1]).abs() <= tolerance);
```

Use `with_coordinate_bits` when an algorithm has an explicit coordinate-bit
budget. The value controls only the converted coordinate magnitude; it does not
prove that every later arithmetic expression is safe. Use `try_with_scale` or
`try_with_scale_and_coordinate_bits` when a caller supplies the scale and
invalid or unsafe scales must be rejected.

## Fixed-scale ratios

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

```rust
use i_float::int::number::unit_ratio::UnitRatio;
use i_float::int::point::IntPoint;

let quarter = UnitRatio::<i32>::from_int(1, 4);
let half = UnitRatio::<i32>::half();

assert_eq!(quarter.scale(10), 3);
assert_eq!(quarter.scale(-10), -3);
assert_eq!(quarter.mid(half), UnitRatio::from_int(3, 8));

let point = IntPoint::new(100, -40);
assert_eq!(quarter.scale_point(point), IntPoint::new(25, -10));
```

Constructors currently expect valid input. In particular, `new` expects a
stored value between zero and `DENOMINATOR`, `from_float` expects a finite value
between zero and one, and `from_int` expects `0 <= numerator <= denominator`.
These preconditions are checked by debug assertions.

## Features

| Feature | Default | Description |
| --- | --- | --- |
| `core` | yes | Integer and floating-point primitives, adapters, and triangle predicates |
| `serde` | no | Enables serialization for supported geometry types and also enables `core` |
| `glam` | no | Adds conversions for `glam::Vec2`, `DVec2`, and `IVec2` and also enables `core` |


## License

Licensed under the MIT License. See the `LICENSE` file.