try_from_degrees rounds away from the nearest sixteenth at two f32 inputs

オープン 初心者向け
#79 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
84/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
rust
領域
embedded-iot

調査の方向性

src/lib.rs:441から始め、既存のties_round_half_away_from_zeroテストとthe_rejection_boundaries_are_exact_and_closedテストを読みます。報告された2つのf32値と、文書化されたf64オラクルを確認し、内部の半LSB境界のカバレッジを追加して、try_from_degreesが文書化された丸め値を返し、拒否の動作を変更しないことを確認します。

索引モデルが issue の本文から書いたものです。

説明

audit:SBOS663A bug impact:field-visible

Celsius::try_from_degrees documents its rounding as:

Values are rounded to the nearest
sixteenth of a degree, half away from zero.

src/lib.rs:404-405

It does not do that for two inputs. Both are the f32 immediately below
±1/32 — strictly nearer to zero than to one sixteenth, so both must round
to 0. Both round to ±1.

Measured

Exhaustive, not sampled: the function was transcribed verbatim into a
scratch binary and run under rustc -O against an f64 oracle over
all 2^32 f32 bit patterns.

exhaustive sweep of all 2^32 f32 inputs
TOTAL DISAGREEMENTS: 2

  bits=0x3cffffff  x= 3.12499981373548508e-2  driver=Ok(1)   documented=Ok(0)
  bits=0xbcffffff  x=-3.12499981373548508e-2  driver=Ok(-1)  documented=Ok(0)

The oracle applies the documented contract in f64: scale by 16 (exact),
round half away from zero, then reject if the rounded value leaves
-2048..=2047. Two disagreements, and no others anywhere in the domain.

Cause

src/lib.rs:441:

let rounded = if scaled >= 0.0 { scaled + 0.5 } else { scaled - 0.5 };

degrees * 16.0 is exact — multiplying by a power of two. The error is in
the half-add. For x = 0.031249998137354851, scaled is 0.49999997,
and 0.49999997f32 + 0.5f32 is 0.99999997 exactly, which is not
representable in binary32; it rounds to 1.0 (ties-to-even against
0.99999994). Truncation then yields 1 instead of 0.

So the tie test happens after a rounding step that can manufacture a tie
that the input did not have.

Scope

Narrow but real. try_from_degrees is the public boundary feeding
set_low_limit / set_high_limit, so an affected input programs a
threshold one LSB (0.0625 °C) away from its advertised value. The two
inputs are not values anyone types as a decimal literal; they arise from
computed floats.

This is a defect against the driver's own documented contract, not
against the datasheet — SBOS663A §7.5.2 specifies the 0.0625 °C
resolution and two's-complement format, and says nothing about how an
arbitrary float should reach a representable value. Rounding policy is
driver policy, as it is for snap_hysteresis in #76.

Why the existing tests miss it

ops_tests covers exact ties (ties_round_half_away_from_zero,
src/lib.rs:4079) and the outer rejection boundaries
(the_rejection_boundaries_are_exact_and_closed, src/lib.rs:4106).
Neither covers the representable neighbours just inside a tie, which is
precisely where the half-add misbehaves.

Options

  1. Round without an intermediate half-add. Compare against the tie
    directly, or perform the add in a wider type. Deletes the failure mode
    rather than special-casing it.
  2. Widen to f64 for the rounding step only. One cast; no_std safe;
    the oracle above is exactly this and is correct over the whole domain.
  3. Document the exception. Cheapest, but the contract sentence would
    have to name two specific bit patterns, which is worse than fixing it.

Any of 1 or 2 changes observable output for two inputs, so it wants a
changelog-visible commit.

Suggested test

Enumerate every internal half-LSB boundary and its two f32 neighbours
(12,285 cases) against an independent oracle, rather than a hand-picked
list. The full 2^32 sweep runs in ~2 s on 16 threads if you ever want it
as a one-off.

Provenance

Raised by the datasheet compliance audit of PR #77, then reproduced
independently. Not a regression — the behaviour predates #77; it was
simply never asserted.

主要言語
Rust
スター
2
フォーク
7
PR マージ指標
30日以内にマージされた PR はありません

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

OpenDevicePartnership/tmp108 のほかの issue

OpenDevicePartnership/tmp108 の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。