Skip to content

Use IEEE comparison in binindex - #1010

Open
andreasnoack wants to merge 1 commit into
masterfrom
an/binindex-ieee-lt
Open

Use IEEE comparison in binindex#1010
andreasnoack wants to merge 1 commit into
masterfrom
an/binindex-ieee-lt

Conversation

@andreasnoack

Copy link
Copy Markdown
Member

Motivation

binindex locates the bin of an observation with searchsortedfirst/searchsortedlast, which compare with isless by default. Under isless, -0.0 sorts strictly below 0.0, so an observation of -0.0 would land in a different bin than 0.0. The current code works around this by passing by=_normalize_zero for vector edges, keeping a separate AbstractRange method without by to avoid losing Base's arithmetic fast path, and rejecting ranges that contain -0.0 in the Histogram constructor since that method could not handle them.

Passing lt = < instead gives IEEE semantics directly: -0.0 < 0.0 is false, so the two zeros are equal and no normalization is needed. NaN compares false with everything, so it still ends up outside the edges and is dropped by push! as before. Base's arithmetic range method accepts the resulting Lt ordering, so the fast path is kept.

Changes

  • _edge_binindex becomes a single method using lt = <; _normalize_zero and the AbstractRange method are removed.
  • The constructor check rejecting ranges containing -0.0 is removed, since its reason no longer applies. Such ranges now bin identically to the corresponding ranges with 0.0.
  • Tests: the two @test_throws for -0.0 ranges are replaced by equality tests, and explicit tests that NaN observations are dropped are added for both closed values and both edge types.

< is also cheaper than isless. fit(Histogram, v, edges) on 1e6 Float64 observations with 100 bins, on an M-series Mac:

edges master this PR
range 10.4 ms 8.1 ms
range, Float32 data 10.7 ms 8.1 ms
range, 2D 23.0 ms 17.4 ms
Vector{Float64} 34.2 ms 15.7 ms

Downstream packages

Bin assignment is unchanged for all inputs except that ranges containing -0.0 are now accepted instead of throwing. The removed helper _normalize_zero was internal. A GitHub code search found no package referencing _normalize_zero or the removed ArgumentError message.

Consumers of StatsBase.Histogram that were checked and go through fit/binindex unchanged: Plots, StatsPlots, Makie (hist, stephist, datashader), AlgebraOfGraphics, UnicodePlots, PairPlots, BAT, FHist, RadiationSpectra, LegendSpecFits. None of them depends on the -0.0 range check or on _normalize_zero.

Before merging, any downstream package that would break because of this change must be fixed first. None has been identified so far; if one turns up it should be listed here.

🤖 Generated with Claude Code

Pass `lt = <` to `searchsortedfirst`/`searchsortedlast` in `_edge_binindex`
instead of relying on `isless`. Since `-0.0 < 0.0` is false, -0.0 and 0.0 are
binned identically without normalizing the inputs, so `_normalize_zero`, the
separate `AbstractRange` method, and the constructor check rejecting ranges
containing -0.0 can all go. `<` is also cheaper than `isless`: `fit(Histogram)`
is about 20% faster with range edges and about 2x faster with vector edges.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant