Skip to content

feat(parser): implement float and double types with endian variants#162

Merged
unclesp1d3r merged 12 commits into
mainfrom
40-parser-implement-float-and-double-types-with-endian-variants
Mar 7, 2026
Merged

feat(parser): implement float and double types with endian variants#162
unclesp1d3r merged 12 commits into
mainfrom
40-parser-implement-float-and-double-types-with-endian-variants

Conversation

@unclesp1d3r
Copy link
Copy Markdown
Member

Summary

Implements issue #40: floating-point type specifiers (float, double, befloat, bedouble, lefloat, ledouble) across the full parser-evaluator pipeline.

  • AST: Added TypeKind::Float and TypeKind::Double variants with endian: Endianness (no signed field -- IEEE 754 handles sign internally). Added Value::Float(f64) variant; Value no longer derives Eq.
  • Parser: 6 new type keywords in parse_type_keyword/type_keyword_to_kind. New parse_float_value grammar function with mandatory decimal point to distinguish from integers.
  • Evaluator: read_float (4 bytes, widened to f64) and read_double (8 bytes) in new evaluator/types/float.rs submodule. Epsilon-aware equality (|a - b| <= f64::EPSILON) with explicit NaN/infinity handling. Ordering operators use partial_cmp directly.
  • Codegen/Strength/Output: All exhaustive matches updated for Float/Double/Value::Float.

Test plan

  • 150 tests pass (cargo test), zero clippy warnings
  • Unit tests: float.rs covers all endianness variants, buffer overrun, offset overflow
  • Equality tests: epsilon-aware, NaN, infinity edge cases (equality.rs)
  • Comparison tests: float ordering, NaN returns None (comparison.rs)
  • Integration tests: float/double rules through evaluate_rules (evaluator_tests.rs)
  • Grammar tests: float literal parsing, type precedence (grammar/tests.rs)
  • Property tests: arb_type_kind includes Float/Double variants
  • Roundtrip test: all 27 type keywords parse and convert without panic

Closes #40

Generated with Claude Code

…pe system

- Added support for `float` and `double` types, including their endian variants `befloat`/`lefloat` and `bedouble`/`ledouble`.
- Removed the note about the absence of floating-point types in the type system section.
- Updated the development phases to reflect the removal of floating-point types from the upcoming advanced types feature.

This enhances the documentation to accurately represent the current capabilities of the magic file compatibility and type system.

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…on and equality handling

- Implemented reading and handling of `float` and `double` types, including endian support.
- Enhanced comparison functions to support `Value::Float`, including partial comparisons and epsilon-aware equality checks.
- Added comprehensive tests for float and double handling, ensuring correct behavior for edge cases like NaN and infinity.
- Updated the evaluator's type reading API to include float and double types.

This update improves the evaluator's capability to handle floating-point numbers, enhancing its overall functionality.

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…on and parsing

- Introduced `TypeKind::Float` and `TypeKind::Double` enums to represent 32-bit and 64-bit floating-point types, respectively, with endian support.
- Implemented serialization for `Value::Float` and `Value::Double`, ensuring correct formatting in output.
- Enhanced parsing capabilities to recognize floating-point literals, including support for scientific notation.
- Added comprehensive unit tests for serialization, parsing, and value comparison of float and double types.

This update expands the type system to include floating-point numbers, improving the library's functionality and usability.

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
- Introduced new tests for evaluating float and double rules, covering equality, inequality, less than, and no match scenarios.
- Enhanced the test suite for the evaluator to ensure correct handling of floating-point comparisons and edge cases.
- Updated property tests to include float and double types in the generation strategies.

This update strengthens the testing framework for floating-point types, ensuring robust evaluation behavior.

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Copilot AI review requested due to automatic review settings March 7, 2026 02:07
@unclesp1d3r unclesp1d3r linked an issue Mar 7, 2026 that may be closed by this pull request
6 tasks
@dosubot dosubot Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Mar 7, 2026
@unclesp1d3r unclesp1d3r self-assigned this Mar 7, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 7, 2026

Caution

Review failed

Failed to post review comments

Summary by CodeRabbit

  • New Features

    • Added 32-bit and 64-bit floating-point type support with endianness variants (native, little-endian, big-endian).
    • Floating-point value literals now supported in rules with scientific notation.
    • Epsilon-aware float equality and IEEE 754 partial ordering for comparisons.
    • New public API functions to read floating-point values from buffers.
  • Documentation

    • Updated API reference and guides with floating-point type details and comparison semantics.

Walkthrough

Adds IEEE‑754 32-bit float and 64-bit double support with endianness variants across parser, AST, evaluator (readers, coercion, comparison, equality), output formatting, RuleMatch.type_kind, and tests.

Changes

Cohort / File(s) Summary
AST & Public Types
src/parser/ast.rs
Added TypeKind::Float/Double { endian }, Value::Float(f64), updated bit widths, removed Eq derive from Value.
Parser & Grammar
src/parser/grammar/mod.rs, src/parser/grammar/tests.rs, src/parser/types.rs
Parse float literals and new keywords (float, befloat, lefloat, double, bedouble, ledouble); float parse attempted before integer; tests adjusted.
Evaluator: Type Readers
src/evaluator/types/float.rs, src/evaluator/types/mod.rs, src/evaluator/types/tests.rs
New read_float/read_double honoring endianness, bounds checks, re-exported; unit tests for endianness/offset/overrun.
Evaluator: Operators
src/evaluator/operators/equality.rs, src/evaluator/operators/comparison.rs
Epsilon-aware float equality and IEEE‑754 partial_cmp ordering for floats; tests for NaN/Infinity and cross-type behavior.
Evaluator: Strength & Match Length
src/evaluator/strength.rs, src/output/mod.rs
Updated numeric specificity grouping and zero-length numeric contribution; match length now uses actual type width for numeric types including floats.
Evaluation Surface
src/evaluator/mod.rs, src/evaluator/engine/mod.rs, src/evaluator/tests.rs, src/tests.rs
Added public type_kind: TypeKind field to RuleMatch and populated it where matches are constructed and in tests.
Output / Serialization
src/output/json.rs, src/parser/codegen.rs, src/build_helpers.rs
Format Value::Float as hex in JSON/hex output, serialize new TypeKind/Value variants, and added build helper tests.
Tests & Properties
tests/evaluator_tests.rs, tests/property_tests.rs, src/evaluator/operators/*, src/evaluator/types/tests.rs, src/build_helpers.rs
Extensive unit/integration/property tests added/extended for reading, coercion, comparison, equality, and evaluation of floats/doubles across endianness.
Docs / Feature Matrix
AGENTS.md, docs/*
Updated docs to document float/double types, keywords, epsilon/NaN comparison semantics, examples, and roadmap/status text.

Sequence Diagram

sequenceDiagram
    participant Client as Rule/Tester
    participant Parser as Parser
    participant Evaluator as Evaluator
    participant Reader as FloatReader
    participant Operators as Operators
    participant Output as Formatter

    Client->>Parser: define rule with TypeKind::Float/Double
    Parser->>Evaluator: emit MagicRule(TypeKind::Float/Double)
    Evaluator->>Reader: read_typed_value(buffer, offset, Float/Double)
    Reader->>Reader: validate window and deserialize (f32/f64, endian)
    Reader->>Evaluator: return Value::Float(f64)
    Evaluator->>Operators: compare_values(Value::Float, other, Operator)
    Operators->>Operators: equality -> floats_equal (epsilon, NaN/infty rules)
    Operators-->>Evaluator: boolean result
    Evaluator->>Output: produce MatchResult(Value::Float, type_kind)
    Output->>Client: formatted/serialized output (hex/JSON)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐰 I hopped into bits both small and wide,
f32 and f64 now run side by side,
Epsilon keeps my equals kind and neat,
NaN skips along on a one‑footed beat,
Hexy bytes shine — a rabbit's tiny stride.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main change: implementing float and double types with endian variants across the parser pipeline.
Description check ✅ Passed Description is well-structured, addresses issue #40, details implementation across all layers (AST, parser, evaluator), and includes test coverage summary.
Linked Issues check ✅ Passed All acceptance criteria from issue #40 are met: TypeKind extended with Float/Double, parser recognizes 6 keywords, evaluator reads 4/8 bytes as IEEE 754, endianness handling implemented, comparison operators support floats with epsilon for equality, comprehensive unit tests added.
Out of Scope Changes check ✅ Passed All changes directly support floating-point type implementation. Added RuleMatch.type_kind field is necessary for correct output length reporting; documentation updates explain new functionality; serialization/codegen changes handle new Float/Double variants.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 40-parser-implement-float-and-double-types-with-endian-variants

Comment @coderabbitai help to get the list of available commands and usage tips.

@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented Mar 7, 2026

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🟢 CI must pass

Wonderful, this rule succeeded.

All CI checks must pass. Release-plz PRs are exempt because they only bump versions and changelogs (code was already tested on main), and GITHUB_TOKEN-triggered force-pushes suppress CI.

  • check-success = coverage
  • check-success = quality
  • check-success = test
  • check-success = test-cross-platform (macos-latest, macOS)
  • check-success = test-cross-platform (ubuntu-22.04, Linux)
  • check-success = test-cross-platform (ubuntu-latest, Linux)
  • check-success = test-cross-platform (windows-latest, Windows)

🟢 Do not merge outdated PRs

Wonderful, this rule succeeded.

Make sure PRs are within 10 commits of the base branch before merging

  • #commits-behind <= 3

@dosubot dosubot Bot added evaluator Rule evaluation engine and logic parser Magic file parsing components and grammar labels Mar 7, 2026
@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented Mar 7, 2026

🧪 CI Insights

Here's what we observed from your CI run for 36218d8.

🟢 All jobs passed!

But CI Insights is watching 👀

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 7, 2026

Codecov Report

❌ Patch coverage is 97.14912% with 13 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/output/json.rs 0.00% 7 Missing ⚠️
src/evaluator/types/float.rs 97.54% 4 Missing ⚠️
src/output/mod.rs 80.00% 1 Missing ⚠️
src/parser/ast.rs 96.42% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation enhancement New feature or request testing Test infrastructure and coverage labels Mar 7, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements IEEE-754 float/double support end-to-end (AST → parser → evaluator → output), including endian variants, to close issue #40 and expand magic-file compatibility.

Changes:

  • Extended AST/type system with TypeKind::Float / TypeKind::Double and Value::Float(f64).
  • Added parsing for float/double type keywords and float literals (with exponent support).
  • Implemented float/double reads in the evaluator and updated operators/output/strength plus test coverage.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/property_tests.rs Expands proptest generators to include Float/Double and float literal values.
tests/evaluator_tests.rs Adds integration tests exercising float/double evaluation.
src/parser/types.rs Recognizes float/double type keywords and maps them to TypeKind.
src/parser/grammar/tests.rs Adds grammar tests for float literals and whitespace behavior.
src/parser/grammar/mod.rs Implements float literal parsing and integrates it into parse_value.
src/parser/codegen.rs Updates codegen serialization for Float/Double and Value::Float.
src/parser/ast.rs Adds new TypeKind variants and Value::Float, adjusts derives/docs/tests.
src/output/mod.rs Extends match-length logic to account for Value::Float.
src/output/json.rs Adds hex formatting support for Value::Float.
src/evaluator/types/tests.rs Adds dispatch/overrun/coercion tests for float/double type reads.
src/evaluator/types/mod.rs Wires new float submodule into typed-value dispatch.
src/evaluator/types/float.rs New module implementing endian-aware float/double reads with tests.
src/evaluator/strength.rs Incorporates Float/Double into default strength heuristics.
src/evaluator/operators/equality.rs Adds epsilon-aware float equality and NaN/inf handling plus tests.
src/evaluator/operators/comparison.rs Enables float ordering via partial_cmp with NaN semantics plus tests.
src/build_helpers.rs Adds tests for codegen serialization of float/double types/values.
AGENTS.md Updates project documentation to reflect new supported types.

Comment thread src/output/mod.rs Outdated
Comment on lines +12 to +36
/// Machine-epsilon threshold used when comparing `Value::Float` operands for
/// equality. Two floats are considered equal when `|a - b| <= FLOAT_EPSILON`.
/// Special values (NaN, infinity) are handled explicitly before the epsilon
/// check.
const FLOAT_EPSILON: f64 = f64::EPSILON;

/// Return `true` when two `f64` values are considered equal under
/// epsilon-aware semantics.
///
/// * **NaN**: NaN is never equal to anything (including itself).
/// * **Infinity**: positive/negative infinity are only equal to the same sign
/// of infinity.
/// * **Finite**: `|a - b| <= FLOAT_EPSILON`.
fn floats_equal(a: f64, b: f64) -> bool {
if a.is_nan() || b.is_nan() {
return false;
}
// Infinities: equal only when same sign (inf - inf = NaN, so must check first).
// Exact comparison is correct here -- infinities have precise IEEE 754 bit patterns.
if a.is_infinite() || b.is_infinite() {
#[allow(clippy::float_cmp)]
return a == b;
}
(a - b).abs() <= FLOAT_EPSILON
}
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Float equality uses an absolute tolerance of f64::EPSILON, but TypeKind::Float values are read as f32 then widened to f64. For most decimal literals (e.g. 0.1), the widened f32 value will differ from the parsed f64 literal by far more than f64::EPSILON, so = comparisons will almost never match except for exactly representable values. Consider either rounding/coercing expected Value::Float to f32 when the rule type is Float (then compare exactly), or switching to a relative/ULP-based tolerance appropriate for f32-derived values.

Copilot uses AI. Check for mistakes.
Comment on lines +76 to +77
TypeKind::Float { endian } => read_float(buffer, offset, *endian),
TypeKind::Double { endian } => read_double(buffer, offset, *endian),
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coerce_value_to_type is called before comparisons, but it currently doesn’t adjust Value::Float based on TypeKind::Float vs TypeKind::Double. Since read_float widens an f32 to f64, expected literals parsed as f64 often won’t match without type-aware rounding. Consider extending coercion so TypeKind::Float rounds/clamps the expected value to f32 (and back to f64) to align comparisons with the on-disk representation.

Copilot uses AI. Check for mistakes.
Comment thread src/parser/grammar/mod.rs
let value: f64 = float_str
.parse()
.map_err(|_| nom::Err::Error(NomError::new(input, nom::error::ErrorKind::MapRes)))?;

Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parse_float_value accepts any f64 that str::parse() returns, including overflow to inf for inputs like 1e309. Non-finite floats can later break JSON serialization (serde_json rejects NaN/±inf) and also make rule codegen produce invalid Rust literals. Consider rejecting non-finite results here (!value.is_finite()) and returning a parse error instead.

Suggested change
// Reject non-finite floats (NaN, +inf, -inf) to keep AST, JSON, and codegen valid
if !value.is_finite() {
return Err(nom::Err::Error(NomError::new(
input,
nom::error::ErrorKind::Float,
)));
}

Copilot uses AI. Check for mistakes.
Comment thread src/parser/codegen.rs
Comment on lines 225 to 230
pub fn serialize_value(value: &Value) -> String {
match value {
Value::Uint(number) => format!("Value::Uint({})", format_number(*number)),
Value::Int(number) => format!("Value::Int({})", format_signed_number(*number)),
Value::Float(f) => format!("Value::Float({f:?})"),
Value::Bytes(bytes) => format!("Value::Bytes({})", format_byte_vec(bytes)),
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

serialize_value formats floats with {f:?}. For non-finite values this yields strings like inf/NaN, which are not valid Rust expressions, and will make generated code fail to compile if such a value is ever produced (e.g. exponent overflow during parsing). Consider serializing floats with a helper that emits f64::NAN / f64::INFINITY / f64::NEG_INFINITY (or f64::from_bits(..)), and uses a Rust-compatible literal format for finite values.

Copilot uses AI. Check for mistakes.
Comment thread tests/evaluator_tests.rs
Comment on lines 4 to +13
//! Evaluator integration tests
//!
//! Tests for confidence calculation, rule ordering, and evaluation behavior
//! through the public `MagicDatabase` API.

use libmagic_rs::{EvaluationConfig, MagicDatabase};
use libmagic_rs::evaluator::evaluate_rules;
use libmagic_rs::{
Endianness, EvaluationConfig, EvaluationContext, MagicDatabase, MagicRule, OffsetSpec,
Operator, TypeKind, Value,
};
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File header says these tests run “through the public MagicDatabase API”, but the new float/double tests import and call evaluator::evaluate_rules directly. Either update the module-level doc comment to match the current approach, or refactor the new tests to exercise the public MagicDatabase API for consistency with the rest of the file.

Copilot uses AI. Check for mistakes.
@dosubot
Copy link
Copy Markdown
Contributor

dosubot Bot commented Mar 7, 2026

Related Documentation

10 document(s) may need updating based on files changed in this PR:

libMagic-rs

API_REFERENCE /libmagic-rs/blob/main/docs/API_REFERENCE.md
View Suggested Changes
@@ -302,6 +302,8 @@
 | `Short { endian, signed }` | 16-bit integer                                           |
 | `Long { endian, signed }`  | 32-bit integer                                           |
 | `Quad { endian, signed }`  | 64-bit integer                                           |
+| `Float { endian }`         | 32-bit IEEE 754 floating-point                           |
+| `Double { endian }`        | 64-bit IEEE 754 floating-point                           |
 | `String { max_length }`    | String data                                              |
 
 ##### 64-bit Integer Types
@@ -318,6 +320,26 @@
 | `ubequad`      | Big        | Unsigned   | Big-endian unsigned 64-bit integer    |
 
 **Version Note:** In v0.2.0, the `Byte` variant changed from a unit variant to a struct variant with a `signed` field.
+
+##### 32-bit Floating-Point Types
+
+The `Float` variant supports three endian variants:
+
+| Type Specifier | Endianness | Description                            |
+| -------------- | ---------- | -------------------------------------- |
+| `float`        | Native     | Native-endian 32-bit IEEE 754 float    |
+| `lefloat`      | Little     | Little-endian 32-bit IEEE 754 float    |
+| `befloat`      | Big        | Big-endian 32-bit IEEE 754 float       |
+
+##### 64-bit Floating-Point Types
+
+The `Double` variant supports three endian variants:
+
+| Type Specifier | Endianness | Description                            |
+| -------------- | ---------- | -------------------------------------- |
+| `double`       | Native     | Native-endian 64-bit IEEE 754 double   |
+| `ledouble`     | Little     | Little-endian 64-bit IEEE 754 double   |
+| `bedouble`     | Big        | Big-endian 64-bit IEEE 754 double      |
 
 #### Operator
 
@@ -343,6 +365,12 @@
 
 **Version Note:** The comparison operators `LessThan`, `GreaterThan`, `LessEqual`, and `GreaterEqual` were added in v0.2.0.
 
+##### Floating-Point Comparison Semantics
+
+Equality operators (`Equal`, `NotEqual`) use epsilon-aware comparison for `Value::Float` operands: two floats are considered equal when `|a - b| <= f64::EPSILON`. NaN is never equal to anything (including itself), and infinities are equal only to the same-signed infinity.
+
+Ordering operators (`LessThan`, `GreaterThan`, `LessEqual`, `GreaterEqual`) use IEEE 754 `partial_cmp` semantics. All NaN comparisons return `false` (NaN is not comparable to any value).
+
 #### Value
 
 Value types for matching.
@@ -351,12 +379,15 @@
 use libmagic_rs::Value;
 ```
 
-| Variant          | Description      |
-| ---------------- | ---------------- |
-| `Uint(u64)`      | Unsigned integer |
-| `Int(i64)`       | Signed integer   |
-| `Bytes(Vec<u8>)` | Byte sequence    |
-| `String(String)` | String value     |
+| Variant          | Description                    |
+| ---------------- | ------------------------------ |
+| `Uint(u64)`      | Unsigned integer               |
+| `Int(i64)`       | Signed integer                 |
+| `Float(f64)`     | 64-bit floating-point value    |
+| `Bytes(Vec<u8>)` | Byte sequence                  |
+| `String(String)` | String value                   |
+
+**Note:** `Value` implements `PartialEq` but not `Eq` due to IEEE 754 NaN semantics (NaN is not equal to itself).
 
 #### Endianness
 

✅ Accepted

Comparison Operators And Compare_Values Helper Pattern
View Suggested Changes
@@ -23,6 +23,7 @@
         (Value::Int(a), Value::Int(b)) => Some(a.cmp(b)),
         (Value::Uint(a), Value::Int(b)) => Some(i128::from(*a).cmp(&i128::from(*b))),
         (Value::Int(a), Value::Uint(b)) => Some(i128::from(*a).cmp(&i128::from(*b))),
+        (Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
         (Value::String(a), Value::String(b)) => Some(a.cmp(b)),
         (Value::Bytes(a), Value::Bytes(b)) => Some(a.cmp(b)),
         _ => None,
@@ -34,9 +35,10 @@
 
 - **Same-type integer comparisons** (`Uint/Uint`, `Int/Int`): Direct native comparison using Rust's `cmp` method
 - **Cross-type integer comparisons** (`Uint/Int`, `Int/Uint`): Uses `i128` coercion to handle the full range of both types without overflow
+- **Float comparisons** (`Float/Float`): Uses `partial_cmp` which returns `Some(Ordering)` for normal values and infinities, `None` for NaN
 - **String comparisons** (`String/String`): Lexicographic comparison
 - **Bytes comparisons** (`Bytes/Bytes`): Lexicographic byte-by-byte comparison
-- **Incompatible type pairs**: Returns `None` (evaluates to `false` in operator functions)
+- **Incompatible type pairs** (including `Float` vs `Int`/`Uint`): Returns `None` (evaluates to `false` in operator functions)
 
 ## Comparison Operator Functions
 
@@ -137,18 +139,21 @@
 
 ## Value Type System
 
-[The `Value` enum in `src/parser/ast.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/f4da22375a440bb5f28bf2bd7e33fbe4e7804f40/src/parser/ast.rs#L119-L130) defines four variants:
+[The `Value` enum in `src/parser/ast.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/f4da22375a440bb5f28bf2bd7e33fbe4e7804f40/src/parser/ast.rs#L119-L130) defines five variants:
 
 ```rust
 pub enum Value {
     Uint(u64),
     Int(i64),
+    Float(f64),
     Bytes(Vec<u8>),
     String(String),
 }
 ```
 
-The pattern handles all meaningful comparison combinations. Same-type comparisons use native Rust ordering. Cross-type integer comparisons require `i128` coercion to ensure mathematical correctness. String and byte comparisons use lexicographic ordering. Incompatible type combinations (such as `Uint` vs `String`) return `None` from `compare_values`, which operators interpret as `false`.
+The `Value` enum derives `PartialEq` but not `Eq` due to IEEE 754 floating-point NaN semantics (`NaN != NaN`).
+
+The pattern handles all meaningful comparison combinations. Same-type comparisons use native Rust ordering. Cross-type integer comparisons require `i128` coercion to ensure mathematical correctness. Float comparisons use `partial_cmp` which returns `Option<Ordering>` to handle NaN. String and byte comparisons use lexicographic ordering. Incompatible type combinations (such as `Uint` vs `String`, or `Float` vs `Int`) return `None` from `compare_values`, which operators interpret as `false`.
 
 ## Usage Examples
 
@@ -182,9 +187,43 @@
 | `Int` | `Int` | `Some(Ordering)` | Direct native comparison |
 | `Uint` | `Int` | `Some(Ordering)` | `i128` coercion prevents overflow |
 | `Int` | `Uint` | `Some(Ordering)` | `i128` coercion prevents overflow |
+| `Float` | `Float` | `Some(Ordering)` or `None` | `partial_cmp`: normal values and infinities return `Some`, NaN returns `None` |
 | `String` | `String` | `Some(Ordering)` | Lexicographic comparison |
 | `Bytes` | `Bytes` | `Some(Ordering)` | Lexicographic byte-by-byte |
+| `Float` | `Int`/`Uint` | `None` | Incompatible (no cross-type coercion) |
 | Mixed incompatible | Mixed incompatible | `None` | Evaluates to `false` |
+
+### IEEE 754 Float Comparison Semantics
+
+Float-to-float comparisons follow IEEE 754 ordering rules via Rust's `partial_cmp`:
+
+- **Normal finite values**: Standard numerical ordering (`1.0 < 2.0`)
+- **Infinities**: `-∞ < all finite values < +∞`; infinities equal themselves
+- **NaN (Not a Number)**: Unordered with respect to all values (including itself). `partial_cmp` returns `None`, causing all comparison operators to return `false`
+- **Subnormal numbers**: Handled correctly by `partial_cmp`
+
+**Float Comparison Examples**:
+
+```rust
+// Normal float comparisons
+compare_values(&Value::Float(1.0), &Value::Float(2.0))  // Some(Less)
+compare_values(&Value::Float(3.14), &Value::Float(2.71))  // Some(Greater)
+
+// Infinity comparisons
+compare_values(&Value::Float(1.0), &Value::Float(f64::INFINITY))  // Some(Less)
+compare_values(&Value::Float(f64::NEG_INFINITY), &Value::Float(1.0))  // Some(Less)
+
+// NaN returns None, making all comparison operators return false
+compare_values(&Value::Float(f64::NAN), &Value::Float(1.0))  // None
+apply_less_than(&Value::Float(f64::NAN), &Value::Float(1.0))  // false
+apply_greater_than(&Value::Float(f64::NAN), &Value::Float(1.0))  // false
+
+// Float vs Int/Uint: incompatible types
+compare_values(&Value::Float(1.0), &Value::Uint(1))  // None
+compare_values(&Value::Int(1), &Value::Float(1.0))  // None
+```
+
+**Note**: Float equality operators use epsilon-aware comparison (`|a - b| <= f64::EPSILON`) rather than `partial_cmp`. See the [Float Epsilon Equality Pattern](https://app.dosu.dev/documents/FIXME) for details on the distinction between ordering and equality semantics for floats.
 
 ## Architectural Pattern and Reusability
 
@@ -252,15 +291,16 @@
 
 - **Basic numeric tests**: Same values, different values, zero, extreme values (`u64::MAX`, `i64::MIN`, `i64::MAX`)
 - **Cross-type integer tests**: `Uint` vs `Int` comparisons with edge cases, especially `u64::MAX` vs `Int(-1)`
+- **Float tests**: Normal values, infinities (`f64::INFINITY`, `f64::NEG_INFINITY`), NaN handling, epsilon edge cases
 - **String tests**: Lexicographic ordering, case sensitivity, empty strings, Unicode handling
 - **Bytes tests**: Lexicographic byte-by-byte comparison, empty byte sequences
-- **Incompatible type tests**: Verify `false` return for mismatched types (e.g., `Uint` vs `String`)
-- **Edge cases**: Boundary values, mathematical edge cases, type coercion edge cases
+- **Incompatible type tests**: Verify `false` return for mismatched types (e.g., `Uint` vs `String`, `Float` vs `Int`)
+- **Edge cases**: Boundary values, mathematical edge cases, type coercion edge cases, NaN unordered semantics
 - **Operator consistency tests**: Verify `compare_values` results match operator semantics
 - **Dispatch tests**: Verify `apply_operator` correctly routes to comparison operator functions
 - **Integration tests**: Real magic rule patterns with version detection, size validation, range checking
 
-The tests maintain the high coverage standard established in the codebase with over 1,400 lines of tests for equality and bitwise operators.
+The tests maintain the high coverage standard established in the codebase with over 1,400 lines of tests for equality and bitwise operators. Implementation details are in `src/evaluator/operators/comparison.rs`.
 
 ## Related Patterns and Topics
 

✅ Accepted

Enum Extension And Exhaustive Match Synchronization
View Suggested Changes
@@ -1,6 +1,6 @@
 # Enum Extension And Exhaustive Match Synchronization
 
-**Enum Extension And Exhaustive Match Synchronization** is a project-specific architectural pattern in [libmagic-rs](https://github.com/EvilBit-Labs/libmagic-rs) that ensures when core enums ([`Operator`](https://github.com/EvilBit-Labs/libmagic-rs/blob/f4da22375a440bb5f28bf2bd7e33fbe4e7804f40/src/parser/ast.rs#L106-L117), [`TypeKind`](https://github.com/EvilBit-Labs/libmagic-rs/blob/f4da22375a440bb5f28bf2bd7e33fbe4e7804f40/src/parser/ast.rs#L80-L104)) are extended with new variants, all exhaustive pattern matches across 7+ files remain synchronized. The pattern leverages Rust's compile-time exhaustiveness checking to prevent runtime failures and maintain consistency across the parser, evaluator, code generator, and test suite.
+**Enum Extension And Exhaustive Match Synchronization** is a project-specific architectural pattern in [libmagic-rs](https://github.com/EvilBit-Labs/libmagic-rs) that ensures when core enums ([`Operator`](https://github.com/EvilBit-Labs/libmagic-rs/blob/f4da22375a440bb5f28bf2bd7e33fbe4e7804f40/src/parser/ast.rs#L106-L117), [`TypeKind`](https://github.com/EvilBit-Labs/libmagic-rs/blob/f4da22375a440bb5f28bf2bd7e33fbe4e7804f40/src/parser/ast.rs#L80-L104), [`Value`](https://github.com/EvilBit-Labs/libmagic-rs/blob/f4da22375a440bb5f28bf2bd7e33fbe4e7804f40/src/parser/ast.rs#L275)) are extended with new variants, all exhaustive pattern matches across 7+ files remain synchronized. The pattern leverages Rust's compile-time exhaustiveness checking to prevent runtime failures and maintain consistency across the parser, evaluator, code generator, and test suite. Enum extensions may also require trait derivation changes (e.g., removing `Eq` when adding IEEE 754 float types).
 
 The pattern exists because libmagic-rs uses a three-layer architecture where AST definitions live in `src/parser/ast.rs`, parser grammar uses nom combinators in `src/parser/grammar.rs`, and evaluator dispatch functions reside in `src/evaluator/*.rs`. Each layer requires explicit handling of all enum variants. When extending the `Operator` enum to add [comparison operators like `<`, `>`, `<=`, `>=`](https://github.com/EvilBit-Labs/libmagic-rs/issues/34), developers must update pattern matches in parser token ordering, operator evaluation, strength scoring, build-time serialization (in two locations), and property test strategies. Missing any of these updates triggers compiler errors due to non-exhaustive matches, but understanding which files need updates and in what order requires project-specific knowledge.
 
@@ -33,7 +33,12 @@
 - **`Quad { endian: Endianness, signed: bool }`**: 64-bit integer with endianness and signedness options
 - **`String { max_length: Option<usize> }`**: Variable-length string with optional maximum length
 
-The [Endianness enum](https://github.com/EvilBit-Labs/libmagic-rs/blob/f4da22375a440bb5f28bf2bd7e33fbe4e7804f40/src/parser/ast.rs#L133-L141) provides `Little`, `Big`, and `Native` byte order options for multi-byte types. Future extensions include [floating-point types (Float, Double, Issue #40)](https://github.com/EvilBit-Labs/libmagic-rs/issues/40) and [date/timestamp types (Date, QDate, Issue #41)](https://github.com/EvilBit-Labs/libmagic-rs/issues/41).
+The [Endianness enum](https://github.com/EvilBit-Labs/libmagic-rs/blob/f4da22375a440bb5f28bf2bd7e33fbe4e7804f40/src/parser/ast.rs#L133-L141) provides `Little`, `Big`, and `Native` byte order options for multi-byte types.
+
+- **`Float { endian: Endianness }`**: 32-bit IEEE 754 floating-point with endianness (no signed field)
+- **`Double { endian: Endianness }`**: 64-bit IEEE 754 double-precision floating-point with endianness (no signed field)
+
+Future extensions include [date/timestamp types (Date, QDate, Issue #41)](https://github.com/EvilBit-Labs/libmagic-rs/issues/41).
 
 ## Exhaustive Match Locations
 
@@ -85,12 +90,18 @@
         TypeKind::Short { endian, signed } => read_short(buffer, offset, *endian, *signed),
         TypeKind::Long { endian, signed } => read_long(buffer, offset, *endian, *signed),
         TypeKind::Quad { endian, signed } => read_quad(buffer, offset, *endian, *signed),
+        TypeKind::Float { endian } => read_float(buffer, offset, *endian),
+        TypeKind::Double { endian } => read_double(buffer, offset, *endian),
         TypeKind::String { max_length } => read_string(buffer, offset, *max_length),
     }
 }
 ```
 
-[Multi-byte types (Short, Long, Quad) include nested exhaustive matches on `Endianness`](https://github.com/EvilBit-Labs/libmagic-rs/blob/f4da22375a440bb5f28bf2bd7e33fbe4e7804f40/src/evaluator/types.rs#L135-L139) using the `byteorder` crate for `Little`, `Big`, and `Native` variants.
+[Multi-byte types (Short, Long, Quad, Float, Double) include nested exhaustive matches on `Endianness`](https://github.com/EvilBit-Labs/libmagic-rs/blob/f4da22375a440bb5f28bf2bd7e33fbe4e7804f40/src/evaluator/types.rs#L135-L139) using the `byteorder` crate for `Little`, `Big`, and `Native` variants. IEEE 754 floating-point types require special handling:
+
+- **Epsilon-aware equality**: Float comparisons use `|a - b| <= f64::EPSILON` rather than exact equality
+- **Partial ordering**: Comparison operators use `partial_cmp` to handle NaN cases (returns `None` for NaN operands)
+- **Special values**: Explicit handling for NaN (never equal to anything, including itself) and infinity (only equal to same-sign infinity)
 
 ### 5. Strength Scoring (src/evaluator/strength.rs)
 
@@ -114,14 +125,14 @@
     TypeKind::String { max_length } => {
         if max_length.is_some() { 25 } else { 20 }
     }
-    TypeKind::Quad { .. } => 16,
-    TypeKind::Long { .. } => 15,
+    TypeKind::Quad { .. } | TypeKind::Double { .. } => 16,
+    TypeKind::Long { .. } | TypeKind::Float { .. } => 15,
     TypeKind::Short { .. } => 10,
     TypeKind::Byte { .. } => 5,
 };
 ```
 
-Strength scores prioritize more specific operators and types for accurate file type detection.
+Strength scores prioritize more specific operators and types for accurate file type detection. Floating-point types (Float, Double) are assigned the same scores as their integer counterparts (Long, Quad) based on bit width.
 
 ### 6. Build-Time Serialization (build.rs AND src/build_helpers.rs)
 
@@ -244,6 +255,20 @@
 
 The PR also enhanced parser numeric literal handling to support the full unsigned 64-bit range (0 to `u64::MAX`), required for magic rules matching values like `0xffffffffffffffff`.
 
+### Float and Double Type Implementation (PR #162)
+
+[PR #162](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) added IEEE 754 floating-point support through `TypeKind::Float` and `TypeKind::Double` variants and a new `Value::Float(f64)` variant, demonstrating the enum extension pattern across 17 changed files. This PR illustrates how enum extensions can cascade to affect trait derivations: the `Value` enum no longer derives `Eq` due to IEEE 754 NaN semantics. All seven exhaustive match locations were updated:
+
+1. **AST definition** (`src/parser/ast.rs`): Added `Float { endian }` and `Double { endian }` variants to `TypeKind` (no signed field -- IEEE 754 handles sign internally). Added `Value::Float(f64)` variant. Removed `Eq` derivation from `Value` enum due to NaN incompatibility.
+2. **Parser grammar** (`src/parser/types.rs`): Implemented parsing for 6 new type keywords (`float`, `befloat`, `lefloat`, `double`, `bedouble`, `ledouble`) in `parse_type_keyword` and `type_keyword_to_kind` functions. Added `parse_float_value` grammar function with mandatory decimal point to distinguish float literals from integers.
+3. **Type reading** (`src/evaluator/types/float.rs`): Created new submodule with `read_float()` (4 bytes, widened to f64) and `read_double()` (8 bytes) functions. Both return `Value::Float(f64)` and include endianness dispatch and comprehensive unit tests covering buffer overrun, offset overflow, and all endianness variants.
+4. **Strength scoring** (`src/evaluator/strength.rs`): Assigned Float types a score of 15 (same as Long) and Double types a score of 16 (same as Quad) based on bit width. Updated value length bonus logic to handle `Value::Float` (no length bonus for numeric types).
+5. **Build-time serialization** (`src/build_helpers.rs`): Updated `serialize_type_kind()` to handle Float and Double variants. Added `serialize_value()` support for `Value::Float`. Tests verify correct serialization of all endianness combinations.
+6. **Property test strategies** (`tests/property_tests.rs`): Extended `arb_type_kind()` to generate Float and Double variants with all endianness options. Extended `arb_value()` to generate `Value::Float` with range `-1e10..1e10`.
+7. **Operator evaluation**: Updated `apply_equal()` and `apply_not_equal()` in `src/evaluator/operators/equality.rs` to use epsilon-aware equality (`|a - b| <= f64::EPSILON`) with explicit NaN and infinity handling. Updated `compare_values()` in `src/evaluator/operators/comparison.rs` to use `partial_cmp` for float ordering, returning `None` for NaN comparisons.
+
+The PR also updated output modules (`src/output/json.rs`, `src/output/mod.rs`) and code generation (`src/parser/codegen.rs`) to handle `Value::Float` in exhaustive matches. Integration tests in `tests/evaluator_tests.rs` verify end-to-end float/double evaluation through `evaluate_rules`.
+
 ### Preemptive Modularization Strategy
 
 [Issue #62](https://github.com/EvilBit-Labs/libmagic-rs/issues/62) recommended creating focused submodules before implementing v0.2.0 features to prevent file oversizing as enums grow. The approach:

✅ Accepted

evaluator /libmagic-rs/blob/main/docs/src/evaluator.md
View Suggested Changes
@@ -32,6 +32,7 @@
 - **`evaluator/types/`** - Type reading and coercion (organized as submodules as of v0.4.2)
   - **`types/mod.rs`** - Public API surface: `read_typed_value`, `coerce_value_to_type`, re-exports type functions
   - **`types/numeric.rs`** - Numeric type handling: `read_byte`, `read_short`, `read_long`, `read_quad` with endianness and signedness support
+  - **`types/float.rs`** - Floating-point type handling: `read_float` (32-bit IEEE 754), `read_double` (64-bit IEEE 754) with endianness support
   - **`types/string.rs`** - String type handling: `read_string` with null-termination and UTF-8 conversion
   - **`types/tests.rs`** - Module tests
 - **`evaluator/strength.rs`** - Rule strength calculation
@@ -85,7 +86,7 @@
 }
 ```
 
-The `Value` type is from `parser::ast::Value` and represents the actual matched content according to the rule's type specification.
+The `Value` type is from `parser::ast::Value` and represents the actual matched content according to the rule's type specification. Note that `Value` implements only `PartialEq` (not `Eq`) due to floating-point NaN semantics.
 
 ### Offset Resolution (`evaluator/offset.rs`)
 
@@ -105,12 +106,14 @@
 
 ### Type Reading (`evaluator/types/`)
 
-Interprets bytes according to type specifications. The types module is organized into submodules for numeric and string type handling (refactored from a single file in v0.4.2):
+Interprets bytes according to type specifications. The types module is organized into submodules for numeric, floating-point, and string type handling (refactored from a single file in v0.4.2):
 
 - **Byte**: Single byte values (signed or unsigned)
 - **Short**: 16-bit integers with endianness
 - **Long**: 32-bit integers with endianness
 - **Quad**: 64-bit integers with endianness
+- **Float**: 32-bit IEEE 754 floating-point with endianness (native, big-endian `befloat`, little-endian `lefloat`)
+- **Double**: 64-bit IEEE 754 floating-point with endianness (native, big-endian `bedouble`, little-endian `ledouble`)
 - **String**: Byte sequences with length limits
 - **Bounds checking**: Prevents buffer overruns
 
@@ -123,6 +126,26 @@
 ```
 
 The `read_byte` function signature changed in v0.2.0 to accept three parameters (`buffer`, `offset`, and `signed`) instead of two, allowing explicit control over signed vs unsigned byte interpretation.
+
+**Floating-Point Type Reading (`evaluator/types/float.rs`):**
+
+```rust
+pub fn read_float(
+    buffer: &[u8],
+    offset: usize,
+    endian: Endianness,
+) -> Result<Value, TypeReadError>
+
+pub fn read_double(
+    buffer: &[u8],
+    offset: usize,
+    endian: Endianness,
+) -> Result<Value, TypeReadError>
+```
+
+- `read_float()` reads 4 bytes and interprets as `f32`, converting to `f64` and returning `Value::Float(f64)`
+- `read_double()` reads 8 bytes and interprets as `f64`, returning `Value::Float(f64)`
+- Both respect endianness specified in `TypeKind::Float` or `TypeKind::Double`
 
 ### Operator Application (`evaluator/operators.rs`)
 
@@ -139,6 +162,24 @@
 
 Comparison operators support numeric comparisons across different integer types using `i128` coercion for cross-type compatibility.
 
+**Floating-Point Operator Semantics:**
+
+Float values (`Value::Float`) work with comparison and equality operators but have special handling:
+
+- **Equality operators** (`==`, `!=`): Use epsilon-aware comparison with `f64::EPSILON` tolerance
+  - Two floats are considered equal when `|a - b| <= f64::EPSILON`
+  - Implementation is in `floats_equal()` helper function (`evaluator/operators/equality.rs`)
+- **Ordering operators** (`<`, `>`, `<=`, `>=`): Use IEEE 754 `partial_cmp` semantics
+  - Standard floating-point ordering: `-∞ < finite values < +∞`
+  - Implementation is in `compare_values()` function (`evaluator/operators/comparison.rs`)
+- **NaN handling**:
+  - `NaN != NaN` returns `true` (NaN is never equal to anything, including itself)
+  - All comparison operations with NaN return `false` (NaN is not comparable)
+- **Infinity handling**:
+  - Positive and negative infinity are only equal to the same sign of infinity
+  - Infinities are ordered correctly: `NEG_INFINITY < finite < INFINITY`
+- **Type mismatch**: Float values cannot be compared with `Int` or `Uint` (returns `false` or `None`)
+
 ```rust
 pub fn apply_operator(
     operator: &Operator,
@@ -172,6 +213,41 @@
     &Operator::LessThan,
     &Value::Int(-1),
     &Value::Uint(0)
+));
+```
+
+**Example with floating-point operators:**
+
+```rust
+use libmagic_rs::parser::ast::{Operator, Value};
+use libmagic_rs::evaluator::operators::apply_operator;
+
+// Epsilon-aware equality
+assert!(apply_operator(
+    &Operator::Equal,
+    &Value::Float(1.0),
+    &Value::Float(1.0 + f64::EPSILON)
+));
+
+// Float ordering
+assert!(apply_operator(
+    &Operator::LessThan,
+    &Value::Float(1.5),
+    &Value::Float(2.0)
+));
+
+// NaN inequality
+assert!(apply_operator(
+    &Operator::NotEqual,
+    &Value::Float(f64::NAN),
+    &Value::Float(f64::NAN)
+));
+
+// Infinity comparison
+assert!(apply_operator(
+    &Operator::LessThan,
+    &Value::Float(f64::NEG_INFINITY),
+    &Value::Float(0.0)
 ));
 ```
 
@@ -362,17 +438,37 @@
 assert_eq!(matches[0].message, "Small value detected");
 ```
 
+**Example with floating-point types:**
+
+```rust
+use libmagic_rs::{evaluate_rules, EvaluationConfig};
+use libmagic_rs::parser::parse_text_magic_file;
+
+// Parse magic rule with float type
+let magic_content = r#"
+0 lefloat 3.14159 Pi constant detected
+0 bedouble >100.0 Large double value
+"#;
+let rules = parse_text_magic_file(magic_content)?;
+
+// IEEE 754 little-endian representation of 3.14159f32
+let buffer = vec![0xd0, 0x0f, 0x49, 0x40];
+let matches = evaluate_rules(&rules, &buffer)?;
+
+assert_eq!(matches[0].message, "Pi constant detected");
+```
+
 ## Implementation Status
 
 - [x] Basic evaluation engine structure
 - [x] Offset resolution (absolute, relative, from-end)
-- [x] Type reading with endianness support (Byte, Short, Long, Quad, String)
+- [x] Type reading with endianness support (Byte, Short, Long, Quad, Float, Double, String)
 - [x] Operator application (Equal, NotEqual, LessThan, GreaterThan, LessEqual, GreaterEqual, BitwiseAnd, BitwiseAndMask)
 - [x] Hierarchical rule processing with child evaluation
 - [x] Error handling with graceful degradation
 - [x] Timeout protection
 - [x] Recursion depth limiting
-- [x] Comprehensive test coverage (100+ tests)
+- [x] Comprehensive test coverage (150+ tests)
 - [ ] Indirect offset support (pointer dereferencing)
 - [ ] Regex type support
 - [ ] Performance optimizations (rule ordering, caching)

✅ Accepted

Float And Double Type Support
View Suggested Changes
@@ -2,17 +2,17 @@
 
 ## Lead Section
 
-Float and Double type support is a **planned feature** for libmagic-rs that will enable detection and evaluation of IEEE 754 floating-point data in binary files. This feature is documented for v0.5.0+ but **not yet implemented** in the codebase. When implemented, it will add six magic file keywords (`float`, `befloat`, `lefloat`, `double`, `bedouble`, `ledouble`) corresponding to 32-bit and 64-bit floating-point types with configurable endianness.
-
-The implementation will require extending [the `TypeKind` enum in `src/parser/ast.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L80-L123) with `Float` and `Double` variants, adding a `Value::Float(f64)` variant to [the `Value` enum](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L277-L288), and implementing buffer reading logic for IEEE 754 binary representation. Critically, the `Eq` derive must be removed from the `Value` enum due to IEEE 754 NaN semantics, which violate Rust's `Eq` trait requirements (NaN != NaN by specification).
-
-This article documents the complete architectural design for float/double support, including AST structure, parser grammar, evaluator logic, strength calculation, comparison operations, and the cascading code changes required across 10+ files to maintain exhaustive pattern matching invariants.
+Float and Double type support is an **implemented feature** (as of PR #162) for libmagic-rs that enables detection and evaluation of IEEE 754 floating-point data in binary files. The implementation adds six magic file keywords (`float`, `befloat`, `lefloat`, `double`, `bedouble`, `ledouble`) corresponding to 32-bit and 64-bit floating-point types with configurable endianness.
+
+The implementation extends [the `TypeKind` enum in `src/parser/ast.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L80-L123) with `Float` and `Double` variants, adds a `Value::Float(f64)` variant to [the `Value` enum](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L277-L288), and implements buffer reading logic for IEEE 754 binary representation. Critically, the `Eq` derive has been removed from the `Value` enum due to IEEE 754 NaN semantics, which violate Rust's `Eq` trait requirements (NaN != NaN by specification).
+
+This article documents the complete architecture for float/double support, including AST structure, parser grammar, evaluator logic, strength calculation, comparison operations, and the cascading code changes across 10+ files required to maintain exhaustive pattern matching invariants.
 
 ## IEEE 754 Type Architecture
 
 ### TypeKind Enum Extensions
 
-[The `TypeKind` enum](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L80-L123) will be extended with two floating-point variants following the same pattern as multi-byte integer types (`Short`, `Long`, `Quad`):
+[The `TypeKind` enum](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L80-L123) has been extended with two floating-point variants following the same pattern as multi-byte integer types (`Short`, `Long`, `Quad`):
 
 ```rust
 pub enum TypeKind {
@@ -92,7 +92,7 @@
 
 ### Value::Float Variant
 
-[The `Value` enum](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L277-L288) will be extended with a new variant:
+[The `Value` enum](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L277-L288) has been extended with a new variant:
 
 ```rust
 pub enum Value {
@@ -108,7 +108,7 @@
 
 ### Critical: Removal of Eq Derive
 
-[The `Value` enum currently derives `Eq`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L278):
+[The `Value` enum](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L278) previously derived `Eq`:
 
 ```rust
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@@ -117,13 +117,13 @@
 }
 ```
 
-The `Eq` derive **must be removed** when adding `Value::Float(f64)` because IEEE 754 floating-point semantics violate Rust's `Eq` trait requirements:
+The `Eq` derive **has been removed** with the addition of `Value::Float(f64)` because IEEE 754 floating-point semantics violate Rust's `Eq` trait requirements:
 
 1. **NaN inequality**: IEEE 754 specifies that `NaN != NaN`, violating reflexivity (the `Eq` trait requires `a == a` for all values)
 2. **Trait contract**: Rust's `Eq` trait is a marker trait indicating reflexive, symmetric, and transitive equality; NaN breaks reflexivity
 3. **Type safety**: Rust's type system prevents deriving `Eq` on types containing `f32` or `f64` to maintain trait correctness
 
-The `Value` enum can retain `PartialEq` for comparison operators, but `Eq` must be removed:
+The `Value` enum now retains `PartialEq` for comparison operators, but `Eq` has been removed:
 
 ```rust
 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]  // Eq removed
@@ -132,7 +132,7 @@
 }
 ```
 
-This is a **breaking change** that cascades to any structs deriving from `Value` (such as `MagicRule`) that currently rely on automatic `Eq` derivation. These structs must either:
+This **breaking change** cascades to any structs deriving from `Value` (such as `MagicRule`) that previously relied on automatic `Eq` derivation. These structs must either:
 - Remove their own `Eq` derive and keep `PartialEq`
 - Implement custom equality that explicitly handles the NaN case
 
@@ -140,7 +140,7 @@
 
 ### read_float and read_double Implementation
 
-Float and double types will be implemented following [the pattern established for integer types in `src/evaluator/types/numeric.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/types/numeric.rs#L132-L161):
+Float and double types are implemented in `src/evaluator/types/float.rs` following [the pattern established for integer types in `src/evaluator/types/numeric.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/types/numeric.rs#L132-L161):
 
 ```rust
 pub fn read_float(
@@ -192,11 +192,11 @@
 }
 ```
 
-Both functions use the `byteorder` crate (already a project dependency) for endianness conversion, following [the pattern in `read_long` and `read_quad`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/types/numeric.rs#L132-L218).
+Both functions use the `byteorder` crate (already a project dependency) for endianness conversion, following [the pattern in `read_long` and `read_quad`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/types/numeric.rs#L132-L218). The implementation uses `LittleEndian::read_f32`, `BigEndian::read_f32`, and `NativeEndian::read_f32` methods (with corresponding `read_f64` for doubles) to interpret byte sequences as IEEE 754 values.
 
 ### Dispatcher Integration
 
-[The `read_typed_value` dispatcher in `src/evaluator/types/mod.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/types/mod.rs#L64-L76) must add Float and Double cases:
+[The `read_typed_value` dispatcher in `src/evaluator/types/mod.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/types/mod.rs#L64-L76) includes Float and Double cases:
 
 ```rust
 pub fn read_typed_value(
@@ -218,14 +218,14 @@
 
 ### IEEE 754 Comparison Semantics
 
-[Comparison operators in `src/evaluator/operators/comparison.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/comparison.rs#L29-L39) must implement IEEE 754 semantics for floating-point values:
-
-- **Equality (`==`)**: `NaN == NaN` returns `false` by IEEE 754 specification
-- **Inequality (`!=`)**: `NaN != NaN` returns `true` by IEEE 754 specification  
-- **Ordering (`<`, `>`, `<=`, `>=`)**: Any comparison with NaN returns `false`
-- **Bitwise operations (`&`, `^`, `~`)**: Not meaningful for floating-point; should return error
-
-Recommended implementation using `f64::partial_cmp`:
+[Comparison operators in `src/evaluator/operators/comparison.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/comparison.rs#L29-L39) implement IEEE 754 semantics for floating-point values using `f64::partial_cmp`:
+
+- **Equality (`==`)**: Uses epsilon-aware comparison (`|a - b| <= f64::EPSILON`) with explicit NaN and infinity handling in `src/evaluator/operators/equality.rs`
+- **Inequality (`!=`)**: Negates epsilon-aware equality; `NaN != NaN` returns `true` by IEEE 754 specification  
+- **Ordering (`<`, `>`, `<=`, `>=`)**: Any comparison with NaN returns `None` (propagates as `false`)
+- **Bitwise operations (`&`, `^`, `~`)**: Not meaningful for floating-point; return error
+
+Implementation using `f64::partial_cmp`:
 
 ```rust
 pub fn compare_values(left: &Value, right: &Value) -> Option<Ordering> {
@@ -241,7 +241,7 @@
 
 ### Cross-Type Comparison Policy
 
-[The existing comparison logic uses `i128` coercion for cross-type integer comparisons](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/comparison.rs#L29-L39). Floating-point values should **not** participate in cross-type coercion:
+[The existing comparison logic uses `i128` coercion for cross-type integer comparisons](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/comparison.rs#L29-L39). Floating-point values **do not** participate in cross-type coercion:
 
 - `Value::Float` compared with `Value::Int` or `Value::Uint` → returns `None` (type mismatch)
 - `Value::Float` compared with `Value::Float` → uses IEEE 754 semantics via `partial_cmp`
@@ -251,7 +251,7 @@
 
 ## Strength Calculation
 
-[The strength scoring system in `src/evaluator/strength.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/strength.rs#L72-L88) assigns confidence points based on type specificity. Float and Double types should be scored similarly to their integer counterparts:
+[The strength scoring system in `src/evaluator/strength.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/strength.rs#L72-L88) assigns confidence points based on type specificity. Float and Double types are scored similarly to their integer counterparts:
 
 ```rust
 strength += match &rule.typ {
@@ -276,7 +276,7 @@
 
 ### TypeKind Serialization
 
-[The `serialize_type_kind` function in `src/parser/codegen.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/codegen.rs#L172-L196) generates Rust code for TypeKind variants during the build process. Float and Double variants must be added following [the pattern for integer types](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/codegen.rs#L172-L196):
+[The `serialize_type_kind` function in `src/parser/codegen.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/codegen.rs#L172-L196) generates Rust code for TypeKind variants during the build process. Float and Double variants have been added following [the pattern for integer types](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/codegen.rs#L172-L196):
 
 ```rust
 TypeKind::Float { endian } => format!(
@@ -293,15 +293,15 @@
 
 ### Critical Synchronization Requirement
 
-The `serialize_type_kind` function appears in **two locations** that must remain synchronized:
+The `serialize_type_kind` function appears in **two locations** that have been synchronized:
 1. `src/parser/codegen.rs` (used for runtime code generation)
 2. `src/build_helpers.rs` (used by `build.rs` for compile-time embedding)
 
-Both functions must be updated identically to prevent malformed built-in rules. This dual-location pattern is a known architectural constraint in libmagic-rs.
+Both functions have been updated identically to support Float and Double variants. This dual-location pattern is a known architectural constraint in libmagic-rs.
 
 ## Property-Based Testing
 
-[The `arb_type_kind` strategy in `tests/property_tests.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/tests/property_tests.rs#L37-L50) generates TypeKind variants for fuzzing. Float and Double generators must be added:
+[The `arb_type_kind` strategy in `tests/property_tests.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/tests/property_tests.rs#L37-L50) generates TypeKind variants for fuzzing. Float and Double generators have been added:
 
 ```rust
 fn arb_type_kind() -> impl Strategy<Value = TypeKind> {
@@ -317,57 +317,59 @@
 
 ## Complete Implementation Checklist
 
-Adding Float and Double types requires synchronized updates across multiple files due to Rust's exhaustive pattern matching. The complete checklist:
+Float and Double types required synchronized updates across multiple files due to Rust's exhaustive pattern matching. The complete implementation:
 
 ### 1. AST Definition
 - **File**: `src/parser/ast.rs`
-- **Change**: Add `Float { endian: Endianness }` and `Double { endian: Endianness }` to `TypeKind` enum
-- **Change**: Add `Float(f64)` to `Value` enum
-- **Critical**: Remove `Eq` derive from `Value` enum
+- **Change**: ✅ Added `Float { endian: Endianness }` and `Double { endian: Endianness }` to `TypeKind` enum
+- **Change**: ✅ Added `Float(f64)` to `Value` enum
+- **Critical**: ✅ Removed `Eq` derive from `Value` enum
 
 ### 2. Parser Grammar
 - **File**: `src/parser/types.rs`
-- **Change**: Add float/double keyword groups to `parse_type_keyword` alt combinator (lines 43-78)
-- **Change**: Add six keyword-to-TypeKind mappings in `type_keyword_to_kind` (lines 112-201)
-- **Ordering**: Longest prefixes first (`bedouble` before `double`, `befloat` before `float`)
+- **Change**: ✅ Added float/double keyword groups to `parse_type_keyword` alt combinator (lines 43-78)
+- **Change**: ✅ Added six keyword-to-TypeKind mappings in `type_keyword_to_kind` (lines 112-201)
+- **Ordering**: ✅ Longest prefixes first (`bedouble` before `double`, `befloat` before `float`)
 
 ### 3. Type Reading Functions
-- **File**: `src/evaluator/types/numeric.rs` (or new `src/evaluator/types/float.rs`)
-- **Change**: Implement `read_float()` and `read_double()` functions
+- **File**: `src/evaluator/types/float.rs` (new file)
+- **Change**: ✅ Implemented `read_float()` and `read_double()` functions
 - **File**: `src/evaluator/types/mod.rs`
-- **Change**: Add Float and Double cases to `read_typed_value()` dispatcher (lines 64-76)
-- **Change**: Export `read_float` and `read_double` functions
+- **Change**: ✅ Added Float and Double cases to `read_typed_value()` dispatcher (lines 64-76)
+- **Change**: ✅ Exported `read_float` and `read_double` functions
 
 ### 4. Strength Scoring
 - **File**: `src/evaluator/strength.rs`
-- **Change**: Add `TypeKind::Float { .. } => 15` and `TypeKind::Double { .. } => 16` cases (lines 72-88)
+- **Change**: ✅ Added `TypeKind::Float { .. } => 15` and `TypeKind::Double { .. } => 16` cases (lines 72-88)
 
 ### 5. Comparison Operators
 - **File**: `src/evaluator/operators/comparison.rs`
-- **Change**: Add `(Value::Float(a), Value::Float(b)) => a.partial_cmp(b)` case to `compare_values` (lines 29-39)
+- **Change**: ✅ Added `(Value::Float(a), Value::Float(b)) => a.partial_cmp(b)` case to `compare_values` (lines 29-39)
+- **File**: `src/evaluator/operators/equality.rs`
+- **Change**: ✅ Implemented epsilon-aware equality with explicit NaN/infinity handling
 
 ### 6. Build-Time Serialization (Dual Locations)
 - **File**: `src/parser/codegen.rs`
-- **Change**: Add Float and Double serialization cases to `serialize_type_kind` (lines 172-196)
+- **Change**: ✅ Added Float and Double serialization cases to `serialize_type_kind` (lines 172-196)
 - **File**: `src/build_helpers.rs`
-- **Critical**: Update identical `serialize_type_kind` function synchronously
+- **Critical**: ✅ Updated identical `serialize_type_kind` function synchronously
 
 ### 7. Property Tests
 - **File**: `tests/property_tests.rs`
-- **Change**: Add Float and Double generators to `arb_type_kind()` strategy (lines 37-50)
+- **Change**: ✅ Added Float and Double generators to `arb_type_kind()` strategy (lines 37-50)
 
 ### 8. Output Formatting
 - **File**: `src/output/json.rs`
-- **Change**: Add `Value::Float(f)` case to `format_value_as_hex` and other formatting functions (lines 255-293)
+- **Change**: ✅ Added `Value::Float(f)` case to formatting functions (lines 255-293)
 
 ### 9. Grammar Parsing
 - **File**: `src/parser/grammar/mod.rs`
-- **Change**: Implement float literal parsing with decimal point requirement
-- **Ordering**: Place float literal parser before integer parser in `parse_value` alt chain
+- **Change**: ✅ Implemented `parse_float_value` grammar function with decimal point requirement
+- **Ordering**: ✅ Placed float literal parser before integer parser in `parse_value` alt chain
 
 ### 10. Additional Exhaustive Matches
-- **Various files**: Rust's compiler will flag any additional non-exhaustive TypeKind or Value pattern matches
-- **Test files**: Update test constructors and fixtures to handle new variants
+- **Various files**: ✅ Updated all non-exhaustive TypeKind and Value pattern matches
+- **Test files**: ✅ Updated test constructors and fixtures to handle new variants
 
 ## Architectural Context and Related Patterns
 
@@ -399,35 +401,43 @@
 
 ## Implementation Status
 
-**Float and Double type support is documented but NOT yet implemented.** As of the latest code examination, the codebase contains:
-
-- ✅ Complete architectural design and implementation patterns documented in knowledge base
-- ✅ Established patterns from integer types (Long, Quad) that can be directly adapted
-- ✅ Existing dependencies (`byteorder` crate) required for implementation
-- ❌ No actual Float or Double TypeKind variants in `src/parser/ast.rs`
-- ❌ No Value::Float variant in the Value enum
-- ❌ No float/double keyword parsing in `src/parser/types.rs`
-- ❌ No read_float or read_double functions in `src/evaluator/types/`
-- ❌ No floating-point literal parsing in `src/parser/grammar/mod.rs`
-
-The feature is planned for v0.5.0+ and requires completing all items in the implementation checklist above.
+**Status: ✅ Implemented in v0.1.0 (PR #162)**
+
+Float and Double type support has been fully implemented and merged. The implementation includes:
+
+- ✅ TypeKind::Float and TypeKind::Double variants with Endianness field
+- ✅ Value::Float(f64) variant (Value no longer derives Eq)
+- ✅ Six type keywords: float, double, befloat, bedouble, lefloat, ledouble
+- ✅ parse_float_value grammar for parsing float literals with mandatory decimal point
+- ✅ read_float and read_double evaluator functions in src/evaluator/types/float.rs
+- ✅ Epsilon-aware equality (f64::EPSILON) with NaN/infinity handling in src/evaluator/operators/equality.rs
+- ✅ IEEE 754 partial_cmp for comparison operators in src/evaluator/operators/comparison.rs
+- ✅ Strength scoring for Float (15 points) and Double (16 points) types
+- ✅ JSON output support for float values
+- ✅ Exhaustive match updates across all affected files (ast.rs, types.rs, mod.rs, codegen.rs, build_helpers.rs, strength.rs, comparison.rs, equality.rs, json.rs)
+- ✅ Property-based test generators in tests/property_tests.rs
+- ✅ Comprehensive unit tests for float reading, endianness, equality semantics, NaN/infinity edge cases
+
+The implementation follows the architectural patterns established for integer types (Long, Quad) and maintains exhaustive pattern matching across 10+ files. All 150 tests pass with zero clippy warnings.
 
 ## Relevant Code Files
 
-| File | Purpose | Changes Required |
-|------|---------|------------------|
-| `src/parser/ast.rs` | AST type definitions | Add Float/Double to TypeKind, Float to Value, remove Eq derive |
-| `src/parser/types.rs` | Type keyword parsing | Add 6 float/double keyword mappings |
-| `src/parser/grammar/mod.rs` | Grammar and literal parsing | Implement float literal parser with decimal point |
-| `src/evaluator/types/mod.rs` | Type reading dispatcher | Add Float/Double dispatch cases |
-| `src/evaluator/types/numeric.rs` | Numeric type readers | Implement read_float and read_double |
-| `src/evaluator/strength.rs` | Strength scoring | Add Float (15) and Double (16) scores |
-| `src/evaluator/operators/comparison.rs` | Comparison operators | Add Float comparison with partial_cmp |
-| `src/parser/codegen.rs` | Code generation | Add Float/Double serialization |
-| `src/build_helpers.rs` | Build-time code gen | Add Float/Double serialization (sync with codegen.rs) |
-| `src/output/json.rs` | JSON output formatting | Add Value::Float formatting |
-| `tests/property_tests.rs` | Property-based tests | Add Float/Double generators |
-| `src/parser/grammar/tests.rs` | Parser tests | Add float/double parsing tests |
+| File | Purpose | Implementation Status |
+|------|---------|----------------------|
+| `src/parser/ast.rs` | AST type definitions | ✅ Float/Double TypeKind variants, Float Value variant, Eq derive removed |
+| `src/parser/types.rs` | Type keyword parsing | ✅ 6 float/double keyword mappings |
+| `src/parser/grammar/mod.rs` | Grammar and literal parsing | ✅ parse_float_value with decimal point requirement |
+| `src/evaluator/types/mod.rs` | Type reading dispatcher | ✅ Float/Double dispatch cases |
+| `src/evaluator/types/float.rs` | Float type readers | ✅ read_float and read_double implementations |
+| `src/evaluator/strength.rs` | Strength scoring | ✅ Float (15) and Double (16) scores |
+| `src/evaluator/operators/comparison.rs` | Comparison operators | ✅ Float comparison with partial_cmp |
+| `src/evaluator/operators/equality.rs` | Equality operators | ✅ Epsilon-aware equality with NaN/infinity handling |
+| `src/parser/codegen.rs` | Code generation | ✅ Float/Double serialization |
+| `src/build_helpers.rs` | Build-time code gen | ✅ Float/Double serialization (synced with codegen.rs) |
+| `src/output/json.rs` | JSON output formatting | ✅ Value::Float formatting |
+| `tests/property_tests.rs` | Property-based tests | ✅ Float/Double generators |
+| `tests/evaluator_tests.rs` | Integration tests | ✅ Float/double rule evaluation tests |
+| `src/parser/grammar/tests.rs` | Parser tests | ✅ Float/double parsing tests |
 
 ---
 

✅ Accepted

Float Epsilon Equality Pattern
View Suggested Changes
@@ -4,9 +4,9 @@
 
 The **Float Epsilon Equality Pattern** is an architectural pattern for implementing epsilon-aware floating-point equality comparisons with explicit handling of IEEE 754 edge cases (NaN and infinity). This pattern addresses the fundamental challenge that floating-point arithmetic introduces precision errors, making exact equality comparisons unreliable for computed values.
 
-In the libmagic-rs project, this pattern represents [planned functionality for v0.3 or later](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/AGENTS.md#L243) to support float and double magic file types. The pattern enforces a critical semantic distinction: equality operators (`=`, `==`, `!=`) use epsilon-based comparison to accommodate floating-point precision limitations, while ordering operators (`<`, `>`, `<=`, `>=`) must use strict IEEE 754 semantics to preserve mathematical ordering properties. [This split exists because epsilon comparison violates transitivity](https://github.com/EvilBit-Labs/libmagic-rs/issues/40), which would break ordering relationships.
-
-The pattern's implementation requires explicit handling of special IEEE 754 values: NaN must never equal anything (including itself), infinities require exact bit-pattern comparison, and signed zeros must be treated as equal. [The planned implementation will use `f32::EPSILON` and `f64::EPSILON` as tolerance thresholds](https://github.com/EvilBit-Labs/libmagic-rs/issues/40) to determine equality for normal floating-point values.
+In the libmagic-rs project, this pattern was implemented in v0.1.0 ([PR #162](https://github.com/EvilBit-Labs/libmagic-rs/pull/162)) to support float and double magic file types. The pattern enforces a critical semantic distinction: equality operators (`=`, `==`, `!=`) use epsilon-based comparison to accommodate floating-point precision limitations, while ordering operators (`<`, `>`, `<=`, `>=`) use strict IEEE 754 semantics to preserve mathematical ordering properties. [This split exists because epsilon comparison violates transitivity](https://github.com/EvilBit-Labs/libmagic-rs/issues/40), which would break ordering relationships.
+
+The pattern's implementation requires explicit handling of special IEEE 754 values: NaN must never equal anything (including itself), infinities require exact bit-pattern comparison, and signed zeros must be treated as equal. [The implementation uses `f64::EPSILON` as the tolerance threshold](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) to determine equality for normal floating-point values.
 
 ## Background and Motivation
 
@@ -20,7 +20,7 @@
 
 Epsilon-based equality comparison treats two floating-point values as equal if they differ by less than a small tolerance threshold called epsilon. The standard approach uses machine epsilon (`f32::EPSILON` for 32-bit floats, `f64::EPSILON` for 64-bit doubles), which represents the smallest value such that `1.0 + epsilon != 1.0` in floating-point arithmetic.
 
-[The planned implementation in libmagic-rs will use the formula `(a - b).abs() < epsilon`](https://github.com/EvilBit-Labs/libmagic-rs/issues/40) to determine equality, allowing values within the tolerance threshold to be considered equal while preserving the ability to distinguish values with meaningful differences.
+[The implementation in libmagic-rs uses the formula `(a - b).abs() <= epsilon`](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) to determine equality, allowing values within the tolerance threshold to be considered equal while preserving the ability to distinguish values with meaningful differences.
 
 ### Why Ordering Must Differ from Equality
 
@@ -40,8 +40,8 @@
 **Equality operators** (`=`, `==`, `!=`):
 - Use epsilon-based comparison for floating-point values
 - Delegate to `floats_equal()` helper function
-- Return true when values differ by less than epsilon
-- [Handle NaN and infinity as special cases](https://github.com/EvilBit-Labs/libmagic-rs/issues/40)
+- Return true when values differ by less than or equal to epsilon
+- Handle NaN and infinity as special cases
 
 **Ordering operators** (`<`, `>`, `<=`, `>=`):
 - Use strict IEEE 754 `partial_cmp()` semantics
@@ -49,14 +49,16 @@
 - Return `None` when comparing NaN values (partial ordering)
 - Preserve mathematical transitivity and total ordering properties (except for NaN)
 
-[The existing operator implementation architecture in libmagic-rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/equality.rs) uses helper functions to centralize type-specific comparison logic, with individual operator functions serving as simple delegators. This pattern will extend naturally to floating-point types when implemented.
+The operator implementation architecture in libmagic-rs uses helper functions to centralize type-specific comparison logic, with individual operator functions serving as simple delegators. This pattern extends naturally to floating-point types.
 
 ### The floats_equal() Helper Function
 
-The core of the pattern is the `floats_equal()` helper function, which implements epsilon-aware equality with IEEE 754 edge case handling. [The planned implementation](https://github.com/EvilBit-Labs/libmagic-rs/issues/40) will follow this logic:
-
-```rust
-fn floats_equal(a: f64, b: f64, epsilon: f64) -> bool {
+The core of the pattern is the `floats_equal()` helper function, which implements epsilon-aware equality with IEEE 754 edge case handling. The implementation in [src/evaluator/operators/equality.rs](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) follows this logic:
+
+```rust
+const FLOAT_EPSILON: f64 = f64::EPSILON;
+
+fn floats_equal(a: f64, b: f64) -> bool {
     // NaN is never equal to anything, including itself
     if a.is_nan() || b.is_nan() {
         return false;
@@ -64,59 +66,57 @@
     
     // Infinities must match exactly (same sign)
     if a.is_infinite() || b.is_infinite() {
+        #[allow(clippy::float_cmp)]
         return a == b;  // Exact comparison for infinities
     }
     
     // Standard epsilon comparison for normal values
-    (a - b).abs() < epsilon
+    (a - b).abs() <= FLOAT_EPSILON
 }
 ```
 
 **Design rationale:**
 
-1. **NaN checks must come first**: [IEEE 754 specifies that NaN is not equal to anything](https://github.com/EvilBit-Labs/libmagic-rs/issues/40), including itself. The epsilon comparison `(NaN - NaN).abs() < epsilon` produces nonsense (NaN < epsilon is always false, but through incorrect logic), so explicit checks are required.
-
-2. **Infinity requires exact comparison**: The naive formula `(inf - inf).abs() < epsilon` fails because `inf - inf = NaN`, which makes the comparison always return false. [Infinities must use exact bit-pattern comparison](https://github.com/EvilBit-Labs/libmagic-rs/issues/40): positive infinity equals only positive infinity, negative infinity equals only negative infinity.
+1. **NaN checks must come first**: IEEE 754 specifies that NaN is not equal to anything, including itself. The epsilon comparison `(NaN - NaN).abs() <= epsilon` produces nonsense (NaN <= epsilon is always false, but through incorrect logic), so explicit checks are required.
+
+2. **Infinity requires exact comparison**: The naive formula `(inf - inf).abs() <= epsilon` fails because `inf - inf = NaN`, which makes the comparison always return false. Infinities must use exact bit-pattern comparison: positive infinity equals only positive infinity, negative infinity equals only negative infinity.
 
 3. **Epsilon comparison for normal values**: Only after ruling out NaN and infinity can the standard epsilon formula safely apply to finite values. This ordering ensures each case is handled with appropriate semantics.
 
-4. **Clippy lint suppression**: Direct float comparison (`a == b` for infinities) requires `#[allow(clippy::float_cmp)]` annotation, as [the project enables the `float_cmp` lint at "warn" level](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/Cargo.toml#L50) to catch inappropriate float comparisons elsewhere in the codebase.
+4. **Clippy lint suppression**: Direct float comparison (`a == b` for infinities) requires `#[allow(clippy::float_cmp)]` annotation, as the project enables the `float_cmp` lint at "warn" level to catch inappropriate float comparisons elsewhere in the codebase.
 
 ### Integration with Value Enum
 
-[The current `Value` enum in libmagic-rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L277-L288) supports only `Uint`, `Int`, `Bytes`, and `String` variants. Float support will require adding new variants:
+The `Value` enum in libmagic-rs supports floating-point values through a unified `Float` variant that stores `f64`:
 
 ```rust
 pub enum Value {
     Uint(u64),
     Int(i64),
-    Float(f32),      // New: IEEE 754 single precision
-    Double(f64),     // New: IEEE 754 double precision
+    Float(f64),      // Stores both 32-bit float and 64-bit double
     Bytes(Vec<u8>),
     String(String),
 }
 ```
 
-The `apply_equal()` function in `equality.rs` will then pattern-match on float variants and delegate to `floats_equal()`:
+Both 32-bit `float` and 64-bit `double` types are widened to `f64` and stored as `Value::Float`. The `apply_equal()` function in `equality.rs` pattern-matches on float variants and delegates to `floats_equal()`:
 
 ```rust
 pub fn apply_equal(left: &Value, right: &Value) -> bool {
-    match (left, right) {
-        (Value::Float(a), Value::Float(b)) => floats_equal(*a as f64, *b as f64, f32::EPSILON as f64),
-        (Value::Double(a), Value::Double(b)) => floats_equal(*a, *b, f64::EPSILON),
-        // ... existing integer, string, bytes cases
-        _ => false,  // Incomparable types
+    if let (Value::Float(a), Value::Float(b)) = (left, right) {
+        return floats_equal(*a, *b);
     }
-}
-```
-
-[Cross-type comparisons between floats and integers](https://github.com/EvilBit-Labs/libmagic-rs/issues/40) will require type coercion, following the existing pattern where [Uint and Int comparisons use i128 intermediate values](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/comparison.rs#L33-L34) to safely handle the full range of both types.
+    compare_values(left, right) == Some(Ordering::Equal)
+}
+```
+
+Cross-type comparisons between floats and integers are not supported; such comparisons return `false` for equality and `None` for ordering.
 
 ## IEEE 754 Edge Case Handling
 
 ### NaN Behavior
 
-[IEEE 754 specifies that NaN (Not-a-Number) is not equal to any value, including itself](https://github.com/EvilBit-Labs/libmagic-rs/issues/40). This property must be explicitly enforced:
+IEEE 754 specifies that NaN (Not-a-Number) is not equal to any value, including itself. This property is explicitly enforced:
 
 - `NaN == NaN` returns `false`
 - `NaN == any_value` returns `false`
@@ -126,7 +126,7 @@
 
 ### Infinity Handling
 
-[Positive and negative infinity are distinct values that can be equal within IEEE 754 semantics](https://github.com/EvilBit-Labs/libmagic-rs/issues/40):
+Positive and negative infinity are distinct values that can be equal within IEEE 754 semantics:
 
 - `+inf == +inf` returns `true`
 - `-inf == -inf` returns `true`
@@ -147,21 +147,20 @@
 
 ### Machine Epsilon
 
-[The planned implementation will use `f32::EPSILON` and `f64::EPSILON`](https://github.com/EvilBit-Labs/libmagic-rs/issues/40) as the epsilon thresholds. These constants represent the smallest value `ε` such that `1.0 + ε ≠ 1.0` in the respective floating-point format:
-
-- `f32::EPSILON` ≈ 1.19 × 10⁻⁷ (approximately 7 decimal digits of precision)
+The implementation uses `f64::EPSILON` as the epsilon threshold. This constant represents the smallest value `ε` such that `1.0 + ε ≠ 1.0` in the f64 floating-point format:
+
 - `f64::EPSILON` ≈ 2.22 × 10⁻¹⁶ (approximately 16 decimal digits of precision)
 
 Machine epsilon represents the fundamental precision limit of floating-point arithmetic and provides a natural threshold for equality comparison.
 
 ### Absolute vs. Relative Epsilon
 
-The pattern as described uses **absolute epsilon**: `|a - b| < epsilon`. This works well for values near 1.0 but has limitations:
+The pattern uses **absolute epsilon**: `|a - b| <= epsilon`. This works well for values near 1.0 but has limitations:
 
 - For very large values (e.g., 10¹⁰), the absolute epsilon becomes insignificant relative to the value magnitude
 - For very small values (e.g., 10⁻¹⁰), the absolute epsilon may be too large, causing distinct values to compare as equal
 
-More sophisticated implementations may use **relative epsilon**: `|a - b| < epsilon * max(|a|, |b|)`, which scales the tolerance to the magnitude of the operands. However, [the issue #40 specification indicates absolute epsilon will be used](https://github.com/EvilBit-Labs/libmagic-rs/issues/40), likely for simplicity and compatibility with the original libmagic behavior.
+More sophisticated implementations may use **relative epsilon**: `|a - b| < epsilon * max(|a|, |b|)`, which scales the tolerance to the magnitude of the operands. However, the implementation uses absolute epsilon for simplicity and compatibility with the original libmagic behavior.
 
 ### ULP-Based Comparison
 
@@ -210,47 +209,54 @@
 
 The pattern should be validated with property-based tests using tools like `proptest`:
 
-- **Reflexivity** (for non-NaN): For all `x` (not NaN), `floats_equal(x, x, epsilon)` is true
-- **Symmetry**: If `floats_equal(a, b, epsilon)` then `floats_equal(b, a, epsilon)`
+- **Reflexivity** (for non-NaN): For all `x` (not NaN), `floats_equal(x, x)` is true
+- **Symmetry**: If `floats_equal(a, b)` then `floats_equal(b, a)`
 - **Transitivity violation**: Document that epsilon equality is NOT transitive (intentional design choice)
-- **Ordering consistency**: If `a < b` (ordering operator), then `!floats_equal(a, b, epsilon)` should typically be true (with epsilon edge cases documented)
-
-[The existing test infrastructure uses `proptest` for property-based testing](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/tests/property_tests.rs#L37-L50), which will extend naturally to float types.
+- **Ordering consistency**: If `a < b` (ordering operator), then `!floats_equal(a, b)` should typically be true (with epsilon edge cases documented)
+
+The test infrastructure uses `proptest` for property-based testing, which extends to float types.
 
 ### Integration Testing with Magic Rules
 
-[Magic file rules testing requires constructing `MagicRule` instances with `TypeKind::Float` or `TypeKind::Double`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L80-L123) and evaluating them against IEEE 754-encoded byte buffers. Test cases should include:
+Magic file rules testing requires constructing `MagicRule` instances with `TypeKind::Float` or `TypeKind::Double` and evaluating them against IEEE 754-encoded byte buffers. Test cases should include:
 
 - Parsing float values from big-endian and little-endian byte sequences
 - Evaluating equality conditions with computed float values
 - Handling special value encodings (NaN, infinity in binary form)
 - Cross-type comparisons in magic rule contexts
 
-[The `byteorder` crate v1.5.0](https://github.com/EvilBit-Labs/libmagic-rs/issues/40) provides `read_f32()` and `read_f64()` methods with endianness support, enabling byte-level testing of float parsing and comparison.
+The `byteorder` crate provides `read_f32()` and `read_f64()` methods with endianness support, enabling byte-level testing of float parsing and comparison.
 
 ## Implementation Status in libmagic-rs
 
-[Floating-point types are explicitly listed as "not yet implemented" in libmagic-rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/types/mod.rs#L31-L33), reserved for future development. [The compatibility matrix shows them as "📋 Planned"](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/docs/src/compatibility.md#L82) for v0.3 or later.
-
-Current implementation status:
-- ✅ Integer equality (Uint, Int) with [cross-type coercion via i128](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/comparison.rs#L33-L34)
+Floating-point types were implemented in v0.1.0 ([PR #162](https://github.com/EvilBit-Labs/libmagic-rs/pull/162)) with six type variants to support IEEE 754 single and double precision with endianness control:
+
+- **32-bit float types**: `float` (native), `befloat` (big-endian), `lefloat` (little-endian)
+- **64-bit double types**: `double` (native), `bedouble` (big-endian), `ledouble` (little-endian)
+
+Implementation status:
+- ✅ Integer equality (Uint, Int) with cross-type coercion via i128
 - ✅ String and byte sequence equality
-- ✅ [Operator dispatch architecture](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/equality.rs) ready for float extension
-- ❌ Float/Double `Value` variants not yet defined
-- ❌ `floats_equal()` helper function not yet implemented
-- ❌ Float type parsing and reading not yet implemented
-
-[Issue #40 documents the planned implementation](https://github.com/EvilBit-Labs/libmagic-rs/issues/40), specifying six new type variants (`float`, `befloat`, `lefloat`, `double`, `bedouble`, `ledouble`) to support IEEE 754 single and double precision with endianness variants.
-
-### Existing Epsilon Usage
-
-[The codebase currently uses `f64::EPSILON` only in test assertions](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/tests/evaluator_tests.rs#L31-L32) for comparing metadata values like confidence scores and evaluation times:
-
-```rust
-assert!((result.confidence - expected_confidence).abs() < f64::EPSILON);
-```
-
-This demonstrates awareness of floating-point comparison best practices but is limited to test infrastructure, not type system operations.
+- ✅ Operator dispatch architecture with helper functions
+- ✅ `Value::Float(f64)` variant storing both float and double values
+- ✅ `TypeKind::Float` and `TypeKind::Double` variants with endianness
+- ✅ `floats_equal()` helper function with epsilon-aware comparison
+- ✅ Float type parsing via `read_float()` and `read_double()` in `evaluator/types/float.rs`
+- ✅ Six type keywords (`float`, `befloat`, `lefloat`, `double`, `bedouble`, `ledouble`) in parser
+
+### Test Coverage
+
+The implementation includes comprehensive test coverage:
+
+- **Unit tests**: `evaluator/types/float.rs` covers endianness variants, buffer overrun, offset overflow
+- **Equality tests**: epsilon-aware comparison, NaN, infinity edge cases in `evaluator/operators/equality.rs`
+- **Comparison tests**: float ordering, NaN returns `None` in `evaluator/operators/comparison.rs`
+- **Integration tests**: float/double rules through `evaluate_rules` in `tests/evaluator_tests.rs`
+- **Grammar tests**: float literal parsing, type precedence in `parser/grammar/tests.rs`
+- **Property tests**: `arb_type_kind` includes Float/Double variants in `tests/property_tests.rs`
+- **Roundtrip test**: all 27 type keywords parse and convert without panic
+
+The test suite includes 150 passing tests with zero clippy warnings.
 
 ## Common Pitfalls and Gotchas
 
@@ -319,17 +325,17 @@
 - Too large for values near `1e-15` (may conflate distinct values)
 - Too small for values near `1e10` (may fail to account for computational error)
 
-[The libmagic-rs implementation uses fixed absolute epsilon](https://github.com/EvilBit-Labs/libmagic-rs/issues/40), which is appropriate for magic file type detection where floating-point values typically represent file format metadata in predictable ranges.
+The libmagic-rs implementation uses fixed absolute epsilon, which is appropriate for magic file type detection where floating-point values typically represent file format metadata in predictable ranges.
 
 ## Related Patterns and Concepts
 
 ### Cross-Type Integer Coercion Pattern
 
-The [Cross-Type Integer Coercion Pattern](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/comparison.rs#L33-L34) demonstrates a similar architectural principle: [complex type-pair handling logic is consolidated in helper functions](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/comparison.rs#L29-L39), with operator functions serving as simple delegators. This pattern ensures "single source of truth" for comparison semantics and will extend to float-integer cross-type comparisons.
+The Cross-Type Integer Coercion Pattern demonstrates a similar architectural principle: complex type-pair handling logic is consolidated in helper functions, with operator functions serving as simple delegators. This pattern ensures "single source of truth" for comparison semantics and extends to float comparisons through the `floats_equal()` helper.
 
 ### Comparison Operators and compare_values() Helper Pattern
 
-[The existing operator architecture](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/comparison.rs#L29-L39) uses a `compare_values()` helper that returns `Option<Ordering>`. This design naturally accommodates float comparisons:
+The operator architecture uses a `compare_values()` helper that returns `Option<Ordering>`. This design naturally accommodates float comparisons:
 - `Some(Ordering::Equal | Less | Greater)` for comparable values
 - `None` for incomparable cases (e.g., NaN comparisons, incompatible types)
 
@@ -343,18 +349,18 @@
 
 | File Path | Description |
 |-----------|-------------|
-| [`src/evaluator/operators/equality.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/equality.rs) | Equality operator implementations; will contain `floats_equal()` helper when float support is added |
-| [`src/evaluator/operators/comparison.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/operators/comparison.rs) | Ordering operator implementations with `compare_values()` helper using strict semantics |
-| [`src/parser/ast.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/parser/ast.rs#L277-L288) | `Value` enum definition; will add `Float` and `Double` variants |
-| [`src/evaluator/types/mod.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/src/evaluator/types/mod.rs#L31-L33) | Type reading implementations; float marked as "not yet implemented" |
-| [`tests/evaluator_tests.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/tests/evaluator_tests.rs#L31-L32) | Test examples using `f64::EPSILON` for metadata comparisons |
-| [`tests/property_tests.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b545cb001b42856f34f80c4192a4c12ed229b651/tests/property_tests.rs#L37-L50) | Property-based testing infrastructure that will extend to float types |
-| [`Cargo.toml`](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/Cargo.toml#L50) | Project configuration enabling `float_cmp` clippy lint at "warn" level |
+| [`src/evaluator/operators/equality.rs`](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) | Equality operator implementations with `floats_equal()` helper and `FLOAT_EPSILON` constant |
+| [`src/evaluator/operators/comparison.rs`](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) | Ordering operator implementations using strict IEEE 754 `partial_cmp()` semantics |
+| [`src/parser/ast.rs`](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) | `Value::Float(f64)` variant and `TypeKind::Float`/`TypeKind::Double` definitions |
+| [`src/evaluator/types/float.rs`](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) | `read_float()` and `read_double()` implementations with endianness support |
+| [`src/parser/types.rs`](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) | Six type keywords (`float`, `befloat`, `lefloat`, `double`, `bedouble`, `ledouble`) |
+| [`tests/evaluator_tests.rs`](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) | Integration tests for float/double magic rules |
+| [`tests/property_tests.rs`](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) | Property-based testing with `arb_type_kind` including float types |
 
 ## References
 
 - [IEEE 754 Floating-Point Standard](https://en.wikipedia.org/wiki/IEEE_754) - Official specification for floating-point arithmetic
-- [libmagic-rs Issue #40: Float and Double Type Implementation](https://github.com/EvilBit-Labs/libmagic-rs/issues/40) - Detailed specification of planned float support
-- [libmagic-rs Compatibility Matrix](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/docs/src/compatibility.md#L82) - Status of float type support
+- [libmagic-rs PR #162: Float and Double Type Implementation](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) - Implementation pull request with full code changes
+- [libmagic-rs Issue #40: Float and Double Type Implementation](https://github.com/EvilBit-Labs/libmagic-rs/issues/40) - Original specification and design discussion
 - [Comparing Floating Point Numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/) - Comprehensive guide to floating-point comparison approaches
 - [What Every Computer Scientist Should Know About Floating-Point Arithmetic](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) - Classic paper on floating-point behavior

✅ Accepted

magic-format /libmagic-rs/blob/main/docs/src/magic-format.md
View Suggested Changes
@@ -150,6 +150,33 @@
 8       uquad     >0x8000000000000000 (unsigned 64-bit check)
 ```
 
+### Floating-Point Types
+
+| Type       | Size    | Endianness    | IEEE 754 |
+| ---------- | ------- | ------------- | -------- |
+| `float`    | 4 bytes | native        | 32-bit   |
+| `befloat`  | 4 bytes | big-endian    | 32-bit   |
+| `lefloat`  | 4 bytes | little-endian | 32-bit   |
+| `double`   | 8 bytes | native        | 64-bit   |
+| `bedouble` | 8 bytes | big-endian    | 64-bit   |
+| `ledouble` | 8 bytes | little-endian | 64-bit   |
+
+Floating-point types follow IEEE 754 standard. Unlike integer types, float types do not have signed or unsigned variants (the IEEE 754 format handles sign internally).
+
+Examples:
+
+```text
+0       lefloat   =3.14159   File with float value pi
+0       bedouble  >1.0       Double value greater than 1.0
+```
+
+Float comparison behavior:
+
+- **Equality**: Uses epsilon-aware comparison (`f64::EPSILON` tolerance)
+- **Ordering**: Uses IEEE 754 semantics via `partial_cmp`
+- **NaN**: `NaN != NaN`, comparisons with NaN always return false
+- **Infinity**: Positive and negative infinity are properly ordered
+
 ### String Type
 
 Match literal string data:
@@ -384,6 +411,19 @@
 >24     byte    6                   \b, RGBA
 ```
 
+### Floating-Point Values
+
+```text
+# Check for specific float value
+0       lefloat   =3.14159   File with float value pi
+
+# Float comparison
+0       float     >1.0       Float value greater than 1.0
+
+# Double precision
+0       bedouble  =0.45455   PNG image with gamma 0.45455
+```
+
 ## Best Practices
 
 ### 1. Order Rules by Specificity
@@ -461,6 +501,7 @@
 - Relative offsets
 - Indirect offsets (basic)
 - Byte, short, long, quad types (8-bit, 16-bit, 32-bit, 64-bit integers)
+- Float and double types (32-bit and 64-bit IEEE 754 floating-point)
 - String type
 - Comparison operators (equal, not-equal, less-than, greater-than, less-equal, greater-equal)
 - Bitwise AND operator
@@ -471,7 +512,6 @@
 
 - Regex patterns
 - Date/time types
-- Float types
 - 128-bit integer types
 - Use/name directives
 - Default rules
@@ -480,6 +520,7 @@
 
 - **Strength modifiers**: The `!:strength` directive for adjusting rule priority
 - **64-bit integers**: `quad` type family (`quad`, `uquad`, `lequad`, `ulequad`, `bequad`, `ubequad`)
+- **Floating-point types**: `float` and `double` type families (`float`, `befloat`, `lefloat`, `double`, `bedouble`, `ledouble`) with IEEE 754 semantics and epsilon-aware equality
 
 ## Troubleshooting
 

✅ Accepted

parser /libmagic-rs/blob/main/docs/src/parser.md
View Suggested Changes
@@ -104,6 +104,11 @@
 parse_value("\"Hello\"")           // Value::String("Hello".to_string())
 parse_value("\"Line1\\nLine2\"")   // Value::String("Line1\nLine2".to_string())
 
+// Floating-point literals
+parse_value("3.14")                // Value::Float(3.14)
+parse_value("-1.0")                // Value::Float(-1.0)
+parse_value("2.5e10")              // Value::Float(2.5e10)
+
 // Numeric values
 parse_value("123")                 // Value::Uint(123)
 parse_value("-456")                // Value::Int(-456)
@@ -117,10 +122,67 @@
 **Features:**
 
 - ✅ Quoted string parsing with escape sequence support
+- ✅ Floating-point literal parsing with scientific notation support
 - ✅ Numeric literal parsing (decimal and hexadecimal)
 - ✅ Hex byte sequence parsing (with and without `\x` prefix)
 - ✅ Intelligent type precedence to avoid parsing conflicts
 - ✅ Comprehensive escape sequence handling (`\n`, `\t`, `\r`, `\\`, `\"`, `\'`, `\0`)
+
+### Float and Double Type Parsing (`parse_float_value`)
+
+Parses floating-point type specifiers and literals for IEEE 754 single (32-bit) and double-precision (64-bit) values:
+
+```rust
+// Float literals
+parse_float_value("3.14")          // Ok(("", 3.14))
+parse_float_value("-0.5")          // Ok(("", -0.5))
+parse_float_value("1.0e-10")       // Ok(("", 1.0e-10))
+parse_float_value("2.5E+3")        // Ok(("", 2.5e+3))
+```
+
+**Type Keywords:**
+
+Six floating-point type keywords are supported, each mapping to `TypeKind::Float` or `TypeKind::Double` with an `Endianness` field:
+
+- `float` - 32-bit IEEE 754, native endianness → `TypeKind::Float { endian: Endianness::Native }`
+- `befloat` - 32-bit IEEE 754, big-endian → `TypeKind::Float { endian: Endianness::Big }`
+- `lefloat` - 32-bit IEEE 754, little-endian → `TypeKind::Float { endian: Endianness::Little }`
+- `double` - 64-bit IEEE 754, native endianness → `TypeKind::Double { endian: Endianness::Native }`
+- `bedouble` - 64-bit IEEE 754, big-endian → `TypeKind::Double { endian: Endianness::Big }`
+- `ledouble` - 64-bit IEEE 754, little-endian → `TypeKind::Double { endian: Endianness::Little }`
+
+**Float Literal Grammar:**
+
+The `parse_float_value` function recognizes standard floating-point notation with a **mandatory decimal point** to distinguish floats from integers:
+
+```text
+[-]digits.digits[{e|E}[{+|-}]digits]
+```
+
+Examples: `3.14`, `-0.5`, `1.0e-10`, `2.5E+3`
+
+Parsed literals are stored as `Value::Float(f64)` in the AST, regardless of whether the rule uses `float` or `double` (the type determines buffer read size, not literal representation).
+
+**Usage in Magic Rules:**
+
+```rust
+// Native-endian float comparison
+0 float x        // Match any float value
+0 float =3.14    // Match if float equals 3.14
+
+// Big-endian double comparison
+0 bedouble >1.5  // Match if big-endian double > 1.5
+```
+
+**Features:**
+
+- ✅ Six type keywords for float and double with endianness variants
+- ✅ Float literal parsing with decimal point, negative values, scientific notation
+- ✅ `Value::Float(f64)` AST variant for floating-point literals
+- ✅ Type precedence ensures floats parsed before integers (decimal point disambiguates)
+- ✅ Comprehensive test coverage for all endianness variants and literal formats
+
+**Note:** Float and double types do **not** have signed/unsigned variants. IEEE 754 handles sign internally via the sign bit, so all float types use a single `TypeKind` variant with only an `endian` field (no `signed: bool` field).
 
 ## Parser Design Principles
 
@@ -211,7 +273,7 @@
 assert_eq!(rules[0].children.len(), 2); // Two child rules
 ```
 
-The parser distinguishes between signed and unsigned type variants (e.g., `byte` vs `ubyte`, `leshort` vs `uleshort`), mapping them to the `signed` field in `TypeKind::Byte { signed: bool }` and similar type variants. Unprefixed types default to signed in accordance with libmagic conventions.
+The parser distinguishes between signed and unsigned type variants (e.g., `byte` vs `ubyte`, `leshort` vs `uleshort`), mapping them to the `signed` field in `TypeKind::Byte { signed: bool }` and similar type variants. Unprefixed types default to signed in accordance with libmagic conventions. Float and double types do not have signed/unsigned variants; IEEE 754 handles sign internally.
 
 ### Format Detection
 

✅ Accepted

Parser-Evaluator Architecture
View Suggested Changes
@@ -32,12 +32,12 @@
 ```
 
 1. **Preprocessing**: Removes empty lines, processes comments, handles line continuations (backslashes), and parses `!:strength` directives
-2. **Parsing**: Converts preprocessed lines into flat `MagicRule` objects using nom combinators
+2. **Parsing**: Converts preprocessed lines into flat `MagicRule` objects using nom combinators, including parsing float literals with `parse_float_value()` (requiring decimal points to distinguish from integers) and six new type keywords: `float`, `double`, `befloat`, `bedouble`, `lefloat`, `ledouble`
 3. **Hierarchy Building**: Constructs parent-child relationships based on indentation levels (indicated by `>` prefixes)
 
 ### Nom Parser Combinator Implementation
 
-The [grammar module](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/parser/grammar.rs) uses nom 8.0.0 parser combinators for composable, type-safe parsing. The parser handles type specifications for quad (64-bit integers), long (32-bit integers), short (16-bit integers), byte (8-bit integers), and string types, with endianness variants like `quad`, `uquad`, `lequad`, `ulequad`, `bequad`, and `ubequad`. Key combinators include:
+The [grammar module](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/parser/grammar.rs) uses nom 8.0.0 parser combinators for composable, type-safe parsing. The parser handles type specifications for quad (64-bit integers), long (32-bit integers), short (16-bit integers), byte (8-bit integers), float (32-bit IEEE 754), double (64-bit IEEE 754), and string types, with endianness variants like `quad`, `uquad`, `lequad`, `ulequad`, `bequad`, `ubequad`, `float`, `lefloat`, `befloat`, `double`, `ledouble`, and `bedouble`. Key combinators include:
 
 - **`alt`**: Try multiple parsers in order (e.g., parsing different value types)
 - **`tag`**: Match exact string literals like "byte", "leshort", "0x"
@@ -55,7 +55,8 @@
     let (input, value) = alt((
         map(parse_quoted_string, Value::String),   // Try string first
         map(parse_hex_bytes, Value::Bytes),         // Then hex bytes
-        parse_numeric_value,                        // Finally numbers
+        map(parse_float_value, Value::Float),       // Then floats (with decimal)
+        parse_numeric_value,                        // Finally integers
     ))
     .parse(input)?;
     
@@ -85,9 +86,9 @@
 
 **Supporting Enums**:
 - **`OffsetSpec`**: Absolute, Indirect (pointer dereferencing), Relative, FromEnd
-- **`TypeKind`**: Byte, Short, Long, Quad, String (each numeric type with endianness and signedness)
+- **`TypeKind`**: Byte, Short, Long, Quad, Float, Double, String (each numeric type with endianness and signedness where applicable)
 - **`Operator`**: Equal, NotEqual, LessThan, GreaterThan, LessEqual, GreaterEqual, BitwiseAnd, BitwiseAndMask, BitwiseXor, BitwiseNot, AnyValue
-- **`Value`**: Uint, Int, Bytes, String
+- **`Value`**: Uint, Int, Float, Bytes, String (note: `Value` derives only `PartialEq`, not `Eq`, due to IEEE 754 NaN semantics)
 - **`Endianness`**: Little, Big, Native
 - **`StrengthModifier`**: Add, Subtract, Multiply, Divide, Set
 
@@ -97,6 +98,8 @@
 TypeKind::Short { endian: Endianness, signed: bool }
 TypeKind::Long { endian: Endianness, signed: bool }
 TypeKind::Quad { endian: Endianness, signed: bool }
+TypeKind::Float { endian: Endianness }
+TypeKind::Double { endian: Endianness }
 TypeKind::String { max_length: Option<usize> }
 ```
 
@@ -188,7 +191,7 @@
 
 ### Type Interpretation and Endianness
 
-The [types.rs module](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/types.rs) provides safe, bounds-checked reading of typed values including `read_byte()`, `read_short()`, `read_long()`, `read_quad()`, and `read_string()`:
+The [types.rs module](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/types.rs) provides safe, bounds-checked reading of typed values including `read_byte()`, `read_short()`, `read_long()`, `read_quad()`, `read_float()`, `read_double()`, and `read_string()`:
 
 **Byte Reading**:
 ```rust
@@ -232,6 +235,46 @@
 
 The implementation leverages the `byteorder` crate for efficient byte order conversion and uses Rust's [safe `slice::get` method](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/types.rs#L78-L80) for all buffer access, preventing buffer overruns at compile-time.
 
+**Float and Double Reading** (IEEE 754 standard):
+```rust
+pub fn read_float(
+    buffer: &[u8],
+    offset: usize,
+    endian: Endianness
+) -> Result<Value, TypeReadError> {
+    let bytes = buffer.get(offset..offset + 4)
+        .ok_or(TypeReadError::BufferOverrun { ... })?;
+    
+    let value = match endian {
+        Endianness::Little => LittleEndian::read_f32(bytes),
+        Endianness::Big => BigEndian::read_f32(bytes),
+        Endianness::Native => NativeEndian::read_f32(bytes),
+    };
+    
+    // Widen f32 to f64 for uniform Value::Float representation
+    Ok(Value::Float(f64::from(value)))
+}
+
+pub fn read_double(
+    buffer: &[u8],
+    offset: usize,
+    endian: Endianness
+) -> Result<Value, TypeReadError> {
+    let bytes = buffer.get(offset..offset + 8)
+        .ok_or(TypeReadError::BufferOverrun { ... })?;
+    
+    let value = match endian {
+        Endianness::Little => LittleEndian::read_f64(bytes),
+        Endianness::Big => BigEndian::read_f64(bytes),
+        Endianness::Native => NativeEndian::read_f64(bytes),
+    };
+    
+    Ok(Value::Float(value))
+}
+```
+
+Float types follow the IEEE 754 standard with three endianness variants: `befloat`/`bedouble` (big-endian), `lefloat`/`ledouble` (little-endian), and `float`/`double` (native endianness). The `read_float()` function reads 4 bytes and widens to `f64`, while `read_double()` reads 8 bytes directly into `f64`. Both return `Value::Float(f64)` for uniform representation.
+
 **String Reading** uses [SIMD-accelerated `memchr`](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/types.rs#L289-L297) for efficient null-terminator scanning and handles UTF-8 conversion with `String::from_utf8_lossy`.
 
 ### Operator Application
@@ -241,6 +284,17 @@
 **Equality with Cross-Type Coercion** (from `equality.rs`):
 ```rust
 pub fn apply_equal(left: &Value, right: &Value) -> bool {
+    // Float epsilon-aware equality: |a - b| <= f64::EPSILON
+    if let (Value::Float(a), Value::Float(b)) = (left, right) {
+        if a.is_nan() || b.is_nan() {
+            return false;  // NaN != anything (including NaN)
+        }
+        if a.is_infinite() || b.is_infinite() {
+            return a == b;  // Infinities exact-match
+        }
+        return (a - b).abs() <= f64::EPSILON;
+    }
+    
     match (left, right) {
         (Value::Uint(a), Value::Uint(b)) => a == b,
         (Value::Int(a), Value::Int(b)) => a == b,
@@ -252,7 +306,7 @@
 }
 ```
 
-The implementation [uses `i128` for cross-type integer comparisons](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/operators/equality.rs#L62-L64) to safely handle the full range of both `u64` and `i64` values without overflow.
+Float comparisons use epsilon-aware equality: two floats are considered equal if `|a - b| <= f64::EPSILON`. Special values are handled explicitly: NaN is never equal to anything (including itself), and infinities use exact bit-pattern comparison. The implementation [uses `i128` for cross-type integer comparisons](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/operators/equality.rs#L62-L64) to safely handle the full range of both `u64` and `i64` values without overflow.
 
 **Comparison Operators** (from `comparison.rs`):
 ```rust
@@ -263,6 +317,8 @@
         // Cross-type integer comparisons via i128 coercion
         (Value::Uint(a), Value::Int(b)) => Some(i128::from(*a).cmp(&i128::from(*b))),
         (Value::Int(a), Value::Uint(b)) => Some(i128::from(*a).cmp(&i128::from(*b))),
+        // Float comparisons use partial_cmp (IEEE 754 semantics)
+        (Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
         (Value::String(a), Value::String(b)) => Some(a.cmp(b)),
         (Value::Bytes(a), Value::Bytes(b)) => Some(a.cmp(b)),
         _ => None,
@@ -270,7 +326,7 @@
 }
 ```
 
-Comparison operators (`<`, `>`, `<=`, `>=`) use `compare_values` to perform ordering comparisons. Same-type comparisons use native Rust ordering, while cross-type integer comparisons use `i128` coercion to safely compare `u64` and `i64` values without overflow. Incomparable type combinations (e.g., integers and strings) return `None` and evaluate to false.
+Comparison operators (`<`, `>`, `<=`, `>=`) use `compare_values` to perform ordering comparisons. Same-type comparisons use native Rust ordering, while cross-type integer comparisons use `i128` coercion to safely compare `u64` and `i64` values without overflow. Float comparisons use `partial_cmp()`, which returns `None` for NaN operands (per IEEE 754 semantics). Incomparable type combinations (e.g., integers and strings) return `None` and evaluate to false.
 
 **Bitwise AND Operations** (from `bitwise.rs`):
 ```rust
@@ -498,6 +554,23 @@
 assert_eq!(read_value, Value::Uint(0x1234_5678_90ab_cdef));
 ```
 
+Example with Float and Double types:
+```rust
+// Reading a 32-bit float (IEEE 754)
+let buffer = &[0x00, 0x00, 0x80, 0x3f]; // 1.0f32 in little-endian
+let type_spec = TypeKind::Float { endian: Endianness::Little };
+let offset_pos = offset::resolve_offset(&OffsetSpec::Absolute(0), buffer)?;
+let read_value = types::read_typed_value(buffer, offset_pos, &type_spec)?;
+assert_eq!(read_value, Value::Float(1.0));
+
+// Reading a 64-bit double (IEEE 754)
+let buffer = &[0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; // 1.0f64 in big-endian
+let type_spec = TypeKind::Double { endian: Endianness::Big };
+let offset_pos = offset::resolve_offset(&OffsetSpec::Absolute(0), buffer)?;
+let read_value = types::read_typed_value(buffer, offset_pos, &type_spec)?;
+assert_eq!(read_value, Value::Float(1.0));
+```
+
 ### Hierarchical Rule Evaluation
 
 ```rust

✅ Accepted

Type System And Operator Coverage
View Suggested Changes
@@ -4,7 +4,7 @@
 
 The **Type System And Operator Coverage** in libmagic-rs represents the inventory of data types and comparison operators implemented for detecting file formats through magic rule evaluation. As a pure-Rust replacement for the C libmagic library, libmagic-rs [follows a phased implementation strategy](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/ROADMAP.md) toward achieving [95%+ compatibility with GNU file](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/ROADMAP.md#L49) by version 1.0.0.
 
-The v0.1.x release provided [four basic data types](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/parser/ast.rs#L80-L104) (Byte, Short, Long, and String) with comprehensive endianness and signedness support, alongside [four operators](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/parser/ast.rs#L106-L117) including equality, inequality, and bitwise operations. The [v0.2.0 release](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/ROADMAP.md#L16) added [four comparison operators](https://github.com/EvilBit-Labs/libmagic-rs/pull/104) (<, >, <=, >=) and changed Byte from a unit variant to a signed/unsigned variant. Version 0.3.0 added [64-bit integer support](https://github.com/EvilBit-Labs/libmagic-rs/pull/133) with the Quad type supporting all endianness and signedness variants. Version 0.4.0 added [three additional operators](https://github.com/EvilBit-Labs/libmagic-rs/pull/145) (BitwiseXor, BitwiseNot, and AnyValue) bringing the total to 11 implemented operators. While these primitives enable detection of common file formats including executables, archives, and images, [future versions](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/ROADMAP.md#L18-L53) will expand support to include floating-point types, date/time handling, and regex matching.
+The v0.1.x release provided [four basic data types](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/parser/ast.rs#L80-L104) (Byte, Short, Long, and String) with comprehensive endianness and signedness support, alongside [four operators](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/parser/ast.rs#L106-L117) including equality, inequality, and bitwise operations. The [v0.2.0 release](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/ROADMAP.md#L16) added [four comparison operators](https://github.com/EvilBit-Labs/libmagic-rs/pull/104) (<, >, <=, >=) and changed Byte from a unit variant to a signed/unsigned variant. Version 0.3.0 added [64-bit integer support](https://github.com/EvilBit-Labs/libmagic-rs/pull/133) with the Quad type supporting all endianness and signedness variants. Version 0.4.0 added [three additional operators](https://github.com/EvilBit-Labs/libmagic-rs/pull/145) (BitwiseXor, BitwiseNot, and AnyValue) bringing the total to 11 implemented operators. The v0.1.0 release added [floating-point types](https://github.com/EvilBit-Labs/libmagic-rs/pull/162) (Float and Double with endian variants) to expand format detection capabilities. While these primitives enable detection of common file formats including executables, archives, and images, [future versions](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/ROADMAP.md#L18-L53) will expand support to include date/time handling and regex matching.
 
 This article provides a comprehensive technical reference for the type system and operator implementation, tracking both current capabilities and planned enhancements across the version roadmap to full libmagic compatibility.
 
@@ -43,6 +43,20 @@
 - **Endianness**: Little, Big, and Native variants
 - **Return Type**: `Value::Uint(u64)` for unsigned, `Value::Int(i64)` for signed
 - **Implementation**: [read_quad function](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/types.rs#L229-L299)
+
+#### Float Type
+- **Size**: 32 bits (4 bytes)
+- **Standard**: IEEE 754 single-precision floating-point
+- **Endianness**: Little, Big, and Native variants
+- **Return Type**: `Value::Float(f64)` (widened from f32)
+- **Implementation**: [read_float function](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/src/evaluator/types/float.rs)
+
+#### Double Type
+- **Size**: 64 bits (8 bytes)
+- **Standard**: IEEE 754 double-precision floating-point
+- **Endianness**: Little, Big, and Native variants
+- **Return Type**: `Value::Float(f64)`
+- **Implementation**: [read_double function](https://github.com/EvilBit-Labs/libmagic-rs/blob/main/src/evaluator/types/float.rs)
 
 #### String Type
 - **Size**: Variable length
@@ -60,7 +74,7 @@
 - **Big**: Most significant byte first (common in network protocols)
 - **Native**: System-dependent byte order matching target architecture
 
-All multi-byte integer types (Short, Long, and Quad) support all three endianness variants, enabling detection of files from different architectures and platforms.
+All multi-byte types (Short, Long, Quad, Float, and Double) support all three endianness variants, enabling detection of files from different architectures and platforms.
 
 ## Current Operator Implementation
 
@@ -73,6 +87,7 @@
 #### Equal Operator (=)
 - **Semantics**: Tests exact equality between left and right operands
 - **Cross-Type Coercion**: [Implements intelligent coercion](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/operators.rs#L48-L69) between `Uint` and `Int` by converting both to `i128` to prevent overflow
+- **Float Equality**: Uses epsilon-aware comparison (`|a - b| <= f64::EPSILON`) for `Value::Float`; NaN comparisons always return false
 - **Type Compatibility**: Direct comparison for same types; cross-integer comparison via i128; false for mismatched non-integer types
 - **Implementation**: [apply_equal function](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/operators.rs#L48-L69)
 - **Strength Score**: +10 points (most specific)
@@ -84,28 +99,32 @@
 
 #### LessThan Operator (<)
 - **Semantics**: Returns true if left operand is less than right operand
-- **Type Compatibility**: Works with integers, strings, and bytes; uses i128 coercion for cross-integer comparisons
+- **Type Compatibility**: Works with integers, floats, strings, and bytes; uses i128 coercion for cross-integer comparisons
+- **Float Comparison**: Uses `partial_cmp` with IEEE 754 semantics; NaN comparisons return None (false)
 - **Implementation**: [apply_less_than function](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/operators.rs#L199-L211)
 - **Strength Score**: +6 points
 - **Version**: v0.2.0
 
 #### GreaterThan Operator (>)
 - **Semantics**: Returns true if left operand is greater than right operand
-- **Type Compatibility**: Works with integers, strings, and bytes; uses i128 coercion for cross-integer comparisons
+- **Type Compatibility**: Works with integers, floats, strings, and bytes; uses i128 coercion for cross-integer comparisons
+- **Float Comparison**: Uses `partial_cmp` with IEEE 754 semantics; NaN comparisons return None (false)
 - **Implementation**: [apply_greater_than function](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/operators.rs#L213-L225)
 - **Strength Score**: +6 points
 - **Version**: v0.2.0
 
 #### LessEqual Operator (<=)
 - **Semantics**: Returns true if left operand is less than or equal to right operand
-- **Type Compatibility**: Works with integers, strings, and bytes; uses i128 coercion for cross-integer comparisons
+- **Type Compatibility**: Works with integers, floats, strings, and bytes; uses i128 coercion for cross-integer comparisons
+- **Float Comparison**: Uses `partial_cmp` with IEEE 754 semantics; NaN comparisons return None (false)
 - **Implementation**: [apply_less_equal function](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/operators.rs#L227-L243)
 - **Strength Score**: +6 points
 - **Version**: v0.2.0
 
 #### GreaterEqual Operator (>=)
 - **Semantics**: Returns true if left operand is greater than or equal to right operand
-- **Type Compatibility**: Works with integers, strings, and bytes; uses i128 coercion for cross-integer comparisons
+- **Type Compatibility**: Works with integers, floats, strings, and bytes; uses i128 coercion for cross-integer comparisons
+- **Float Comparison**: Uses `partial_cmp` with IEEE 754 semantics; NaN comparisons return None (false)
 - **Implementation**: [apply_greater_equal function](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/src/evaluator/operators.rs#L245-L261)
 - **Strength Score**: +6 points
 - **Version**: v0.2.0
@@ -157,6 +176,7 @@
 | Uint      | Uint       | ✅ Direct      | ✅ Direct              | ✅         | ✅             | ✅         | ✅         | ✅       |
 | Int       | Int        | ✅ Direct      | ✅ Direct              | ✅         | ✅             | ✅         | ✅         | ✅       |
 | Uint      | Int        | ✅ i128 coerce | ✅ i128 coerce         | ✅         | ✅             | ✅         | ✅         | ✅       |
+| Float     | Float      | ✅ Epsilon     | ✅ partial_cmp         | ❌         | ❌             | ❌         | ❌         | ✅       |
 | Bytes     | Bytes      | ✅ Direct      | ✅ Lexicographic       | ❌         | ❌             | ❌         | ❌         | ✅       |
 | String    | String     | ✅ Direct      | ✅ Lexicographic       | ❌         | ❌             | ❌         | ❌         | ✅       |
 | Mixed     | Mixed      | ❌             | ❌                     | ❌         | ❌             | ❌         | ❌         | ✅       |
@@ -204,11 +224,13 @@
 
 **Status**: Released and [published on crates.io](https://github.com/EvilBit-Labs/libmagic-rs/blob/e925ef6b3f2208fc8805a728ba3de55956f4447a/README.md#L24)
 
-**Type Coverage**: 5 of ~33 types (15%)
+**Type Coverage**: 7 of ~33 types (21%)
 - ✅ Byte
 - ✅ Short (signed/unsigned, all endianness variants)
 - ✅ Long (signed/unsigned, all endianness variants)
 - ✅ Quad (signed/unsigned, all endianness variants)
+- ✅ Float (all endianness variants)
+- ✅ Double (all endianness variants)
 - ✅ String (with optional max_length)
 
 **Operator Coverage**: 4 of ~13 operators (31%)
@@ -234,7 +256,7 @@
 
 **Focus**: [Comparison operators and byte signedness](https://github.com/EvilBit-Labs/libmagic-rs/pull/104)
 
-**Type Coverage**: 5 of ~33 types (15%)
+**Type Coverage**: 7 of ~33 types (21%)
 
 **Type Changes**:
 - ✅ Byte type changed from unit variant to `Byte { signed: bool }` (breaking change)
@@ -259,7 +281,7 @@
 - [Relative offset evaluation](https://github.com/EvilBit-Labs/libmagic-rs/issues/38) (position tracking)
 
 **Coverage**:
-- Types: 5 of ~33 (15%)
+- Types: 7 of ~33 (21%)
 - Operators: 8 of ~13 (62%)
 - Offsets: 5 of 5 (100%)
 
@@ -274,15 +296,18 @@
 - ✅ BitwiseNot (~) - [PR #145](https://github.com/EvilBit-Labs/libmagic-rs/pull/145)
 - ✅ AnyValue (x) - [PR #145](https://github.com/EvilBit-Labs/libmagic-rs/pull/145)
 
+**New Types**:
+- ✅ Float (32-bit IEEE 754) - [PR #162](https://github.com/EvilBit-Labs/libmagic-rs/pull/162)
+- ✅ Double (64-bit IEEE 754) - [PR #162](https://github.com/EvilBit-Labs/libmagic-rs/pull/162)
+
 **Planned New Types**:
 - **Regex and Search**: Pattern matching for text detection ([Issue #39](https://github.com/EvilBit-Labs/libmagic-rs/issues/39))
-- **Floating-Point**: `float`, `double`, `befloat`, `bedouble`, `lefloat`, `ledouble` ([Issue #40](https://github.com/EvilBit-Labs/libmagic-rs/issues/40))
 - **Date/Time**: 32-bit (`date`, `ldate`, variants) and 64-bit (`qdate`, `qldate`, variants) with UTC/local time distinction ([Issue #41](https://github.com/EvilBit-Labs/libmagic-rs/issues/41))
 - **Pascal String**: Length-prefixed string type ([Issue #43](https://github.com/EvilBit-Labs/libmagic-rs/issues/43))
 - **Meta-Types**: `default`, `clear`, `name`, `use`, `indirect` ([Issue #42](https://github.com/EvilBit-Labs/libmagic-rs/issues/42))
 
 **Coverage**:
-- Types: 5 of ~33 (15%)
+- Types: 7 of ~33 (21%)
 - Operators: 11 of ~13 (85%)
 - Offsets: 5 of 5 (100%)
 
@@ -343,8 +368,8 @@
 | v0.1.x | 0% (baseline) | Built-in rules only, 4 basic operators |
 | v0.2.0 | 0% (baseline) | Added comparison operators, quad type |
 | v0.3.0 | ~30% | Indirect/relative offsets |
-| v0.4.0 | ~40% | Bitwise XOR/NOT/any-value operators |
-| v0.5.0 | ~60% | Regex, floating-point, date/time types |
+| v0.4.0 | ~40% | Bitwise XOR/NOT/any-value operators, float/double types |
+| v0.5.0 | ~60% | Regex, date/time types |
 | v0.6.0 | ~80% | Meta-types, remaining edge cases |
 | v1.0.0 | 95%+ | Full feature parity |
 
@@ -366,12 +391,12 @@
 | **64-bit Integer** | `quad` | 8 bytes | Native | ✅ Implemented | v0.2.0 |
 | | `lequad` | 8 bytes | Little | ✅ Implemented | v0.2.0 |
 | | `bequad` | 8 bytes | Big | ✅ Implemented | v0.2.0 |
-| **32-bit Float** | `float` | 4 bytes | Native | 📋 Planned | v0.4.0 |
-| | `lefloat` | 4 bytes | Little | 📋 Planned | v0.4.0 |
-| | `befloat` | 4 bytes | Big | 📋 Planned | v0.4.0 |
-| **64-bit Float** | `double` | 8 bytes | Native | 📋 Planned | v0.4.0 |
-| | `ledouble` | 8 bytes | Little | 📋 Planned | v0.4.0 |
-| | `bedouble` | 8 bytes | Big | 📋 Planned | v0.4.0 |
+| **32-bit Float** | `float` | 4 bytes | Native | ✅ Implemented | v0.1.0 |
+| | `lefloat` | 4 bytes | Little | ✅ Implemented | v0.1.0 |
+| | `befloat` | 4 bytes | Big | ✅ Implemented | v0.1.0 |
+| **64-bit Float** | `double` | 8 bytes | Native | ✅ Implemented | v0.1.0 |
+| | `ledouble` | 8 bytes | Little | ✅ Implemented | v0.1.0 |
+| | `bedouble` | 8 bytes | Big | ✅ Implemented | v0.1.0 |
 | **String** | `string` | Variable | N/A | ✅ Implemented | v0.1.x |
 | | `pstring` | Variable | N/A | 📋 Planned | v0.4.0 |
 | **Date (32-bit)** | `date` | 4 bytes | Native UTC | 📋 Planned | v0.4.0 |
@@ -396,9 +421,9 @@
 | | `use` | N/A | N/A | 📋 Planned | v0.4.0 |
 | | `indirect` | N/A | N/A | 📋 Planned | v0.4.0 |
 
-**Current Coverage**: 5 of 33 types (15%)
-**v0.3.0 Status**: 5 of 33 types (15%)
-**v0.4.0 Status**: 5 of 33 types (15%)
+**Current Coverage**: 7 of 33 types (21%)
+**v0.3.0 Status**: 7 of 33 types (21%)
+**v0.4.0 Status**: 7 of 33 types (21%)
 **v0.5.0 Target**: ~25 of 33 types (76%)
 **v1.0.0 Target**: ~31 of 33 types (94%)
 

✅ Accepted

Note: You must be authenticated to accept/decline updates.

How did I do? Any feedback?  Join Discord

dosubot Bot and others added 2 commits March 7, 2026 02:35
- Add `type_kind` field to `RuleMatch` so output formatting can report
  accurate on-disk byte lengths (fixes hardcoded 8 for all floats)
- Add f32 coercion in `coerce_value_to_type` for `TypeKind::Float` so
  parsed f64 literals round to f32 precision before comparison
- Reject non-finite floats in `parse_float_value` to prevent invalid
  JSON serialization and codegen output
- Handle NaN/infinity in `serialize_value` with valid Rust expressions
  (`f64::NAN`, `f64::INFINITY`, `f64::NEG_INFINITY`)
- Update evaluator test module doc comment to reflect mixed API usage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Copilot AI review requested due to automatic review settings March 7, 2026 03:20
@coderabbitai coderabbitai Bot added the output Result formatting and output generation label Mar 7, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 1 comment.

Comment thread src/parser/grammar/mod.rs
Comment on lines +558 to +565
let value: f64 = float_str
.parse()
.map_err(|_| nom::Err::Error(NomError::new(input, nom::error::ErrorKind::MapRes)))?;

// Reject non-finite floats (NaN, +inf, -inf) to keep AST, JSON, and codegen valid
if !value.is_finite() {
return Err(nom::Err::Error(NomError::new(
input,
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parse_float_value rejects non-finite floats by returning nom::Err::Error, which allows parse_value's alt(...) to backtrack and then parse the same input as an integer prefix (e.g. "1.0e309" becomes Value::Uint(1) with the remainder treated as message). If non-finite float literals are meant to be rejected, return a non-backtracking error (nom::Err::Failure / cut) once the float pattern is recognized, or tighten the numeric parser to require a valid token boundary so it can’t accept a float prefix.

Suggested change
let value: f64 = float_str
.parse()
.map_err(|_| nom::Err::Error(NomError::new(input, nom::error::ErrorKind::MapRes)))?;
// Reject non-finite floats (NaN, +inf, -inf) to keep AST, JSON, and codegen valid
if !value.is_finite() {
return Err(nom::Err::Error(NomError::new(
input,
// At this point, we've definitively recognized a float token; any failure to
// convert it to a finite f64 should be a non-backtracking error so that
// higher-level parsers cannot reinterpret this input as another numeric type.
let value: f64 = match float_str.parse() {
Ok(v) => v,
Err(_) => {
return Err(nom::Err::Failure(NomError::new(
float_str,
nom::error::ErrorKind::Float,
)))
}
};
// Reject non-finite floats (NaN, +inf, -inf) to keep AST, JSON, and codegen valid
if !value.is_finite() {
return Err(nom::Err::Failure(NomError::new(
float_str,

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 7, 2026 03:26
@unclesp1d3r unclesp1d3r review requested due to automatic review settings March 7, 2026 03:26
unclesp1d3r and others added 2 commits March 6, 2026 22:26
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Replace 3.14 literals with 3.125 (exactly representable in binary, not
a PI approximation) and add #[allow(clippy::float_cmp)] for intentional
exact float comparisons in native endian test match guards.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Copilot AI review requested due to automatic review settings March 7, 2026 03:30
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 4 comments.

Comment thread src/parser/ast.rs
Comment on lines +308 to +324
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Value {
/// Unsigned integer value
Uint(u64),
/// Signed integer value
Int(i64),
/// Floating-point value (used for `float` and `double` types)
///
/// # Examples
///
/// ```
/// use libmagic_rs::parser::ast::Value;
///
/// let val = Value::Float(3.14);
/// assert_eq!(val, Value::Float(3.14));
/// ```
Float(f64),
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that Value can contain Float(f64), evaluation can produce NaN/±inf values from file bytes. Since Value (and MatchResult/EvaluationResult) derives Serialize, attempting to serde_json::to_string these results will error because JSON does not support non-finite floats. Consider custom-serializing Value::Float (e.g., as a tagged string/hex bytes when non-finite) or preventing non-finite floats from reaching serializable output types.

Copilot uses AI. Check for mistakes.
Comment thread src/output/json.rs
Comment on lines +292 to +299
Value::Float(f) => {
// Convert to little-endian bytes for consistency
let bytes = f.to_le_bytes();
let mut result = String::with_capacity(16); // 8 bytes * 2 chars per byte
for &b in &bytes {
write!(&mut result, "{b:02x}").expect("Writing to String should never fail");
}
result
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format_value_as_hex encodes Value::Float using f64::to_le_bytes() (always 8 bytes). More generally, numeric variants (Uint/Int/Float) are serialized without considering the on-disk width of the matched type, so JSON value can disagree with MatchResult.length (now derived from type_kind.bit_width()). Consider passing MatchResult.length/TypeKind into this helper so it emits 1/2/4/8-byte little-endian hex consistently (Float=4 bytes, Double=8 bytes).

Copilot uses AI. Check for mistakes.
Comment thread src/output/json.rs
Comment on lines +292 to +299
Value::Float(f) => {
// Convert to little-endian bytes for consistency
let bytes = f.to_le_bytes();
let mut result = String::with_capacity(16); // 8 bytes * 2 chars per byte
for &b in &bytes {
write!(&mut result, "{b:02x}").expect("Writing to String should never fail");
}
result
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are unit tests for format_value_as_hex covering Bytes/String/Uint/Int, but none covering the new Value::Float branch. Adding tests for both 32-bit float (4-byte) and 64-bit double (8-byte) representations (and optionally NaN/±inf) would prevent regressions here.

Copilot uses AI. Check for mistakes.
// Round f64 expected value to f32 precision for TypeKind::Float so that
// parsed f64 literals compare correctly against f32-widened file values.
#[allow(clippy::cast_possible_truncation)]
(Value::Float(v), TypeKind::Float { .. }) => Value::Float(f64::from(*v as f32)),
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coerce_value_to_type converts Value::Float to f32 precision via *v as f32. For large finite literals (e.g. 1e40) this cast overflows to inf, introducing a non-finite expected value even though the parser rejects non-finite float literals. Consider detecting overflow (e.g., cast then check is_finite()) and returning an evaluation error or otherwise handling out-of-range float literals explicitly.

Suggested change
(Value::Float(v), TypeKind::Float { .. }) => Value::Float(f64::from(*v as f32)),
(Value::Float(v), TypeKind::Float { .. }) => {
let narrowed = *v as f32;
if !narrowed.is_finite() {
// If narrowing overflows to a non-finite f32 (e.g., +/-inf, NaN),
// avoid introducing a non-finite expected value and keep the
// original finite literal instead.
Value::Float(*v)
} else {
Value::Float(f64::from(narrowed))
}
}

Copilot uses AI. Check for mistakes.
@unclesp1d3r unclesp1d3r merged commit 94ad404 into main Mar 7, 2026
32 checks passed
@unclesp1d3r unclesp1d3r deleted the 40-parser-implement-float-and-double-types-with-endian-variants branch March 7, 2026 05:12
@github-actions github-actions Bot mentioned this pull request Mar 7, 2026
mergify Bot pushed a commit that referenced this pull request Mar 7, 2026
## 🤖 New release

* `libmagic-rs`: 0.4.3 -> 0.5.0 (⚠ API breaking changes)

### ⚠ `libmagic-rs` breaking changes

```text
--- failure constructible_struct_adds_field: externally-constructible struct adds field ---

Description:
A pub struct constructible with a struct literal has a new pub field. Existing struct literals must be updated to include the new field.
        ref: https://doc.rust-lang.org/reference/expressions/struct-expr.html
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/constructible_struct_adds_field.ron

Failed in:
  field RuleMatch.type_kind in /tmp/.tmpUBXECi/libmagic-rs/src/evaluator/mod.rs:220
  field RuleMatch.type_kind in /tmp/.tmpUBXECi/libmagic-rs/src/evaluator/mod.rs:220

--- failure derive_trait_impl_removed: built-in derived trait no longer implemented ---

Description:
A public type has stopped deriving one or more traits. This can break downstream code that depends on those types implementing those traits.
        ref: https://doc.rust-lang.org/reference/attributes/derive.html#derive
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/derive_trait_impl_removed.ron

Failed in:
  type Value no longer derives Eq, in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:309
  type Value no longer derives Eq, in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:309
  type Value no longer derives Eq, in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:309

--- failure enum_no_repr_variant_discriminant_changed: enum variant had its discriminant change value ---

Description:
The enum's variant had its discriminant value change. This breaks downstream code that used its value via a numeric cast like `as isize`.
        ref: https://doc.rust-lang.org/reference/items/enumerations.html#assigning-discriminant-values
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_no_repr_variant_discriminant_changed.ron

Failed in:
  variant TypeKind::String 4 -> 6 in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:147
  variant TypeKind::String 4 -> 6 in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:147
  variant TypeKind::String 4 -> 6 in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:147

--- failure enum_variant_added: enum variant added on exhaustive enum ---

Description:
A publicly-visible enum without #[non_exhaustive] has a new variant.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#enum-variant-new
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_variant_added.ron

Failed in:
  variant TypeKind:Float in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:128
  variant TypeKind:Double in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:142
  variant TypeKind:Float in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:128
  variant TypeKind:Double in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:142
  variant TypeKind:Float in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:128
  variant TypeKind:Double in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:142
  variant Value:Float in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:324
  variant Value:Float in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:324
  variant Value:Float in /tmp/.tmpUBXECi/libmagic-rs/src/parser/ast.rs:324
```

<details><summary><i><b>Changelog</b></i></summary><p>

<blockquote>

## [0.5.0] - 2026-03-07

### Features

- **parser**: Implement float and double types with endian variants
([#162](#162))
<!-- generated by git-cliff -->
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request evaluator Rule evaluation engine and logic output Result formatting and output generation parser Magic file parsing components and grammar size:XXL This PR changes 1000+ lines, ignoring generated files. testing Test infrastructure and coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parser: implement float and double types with endian variants

2 participants