Comments (11)
@terceiro Thank you for reporting this issue. It is not a bug but these equality comparisons are intentional. The test currently assumes that floating-point arithmetic follows IEEE754.
Could you please check whether enumerable-statistics you built uses i387's extended precision arithmetic?
from enumerable-statistics.
Well, just running rake
from the enumerable-statistics sources on an i386 Debian system reproduces this. The build uses whatever are the default options:
$ git remote -v
origin https://github.com/mrkn/enumerable-statistics.git (fetch)
origin https://github.com/mrkn/enumerable-statistics.git (push)
$ git clean -dxf
$ rake
mkdir -p lib/enumerable/statistics
mkdir -p tmp/i386-linux-gnu/enumerable/statistics/extension/2.7.5/enumerable/statistics
cd tmp/i386-linux-gnu/enumerable/statistics/extension/2.7.5
/usr/bin/ruby2.7 -I. ../../../../../../ext/enumerable/statistics/extension/extconf.rb
checking for struct RRational... no
checking for rb_rational_new()... yes
checking for rb_rational_num()... yes
checking for rb_rational_den()... yes
checking for rb_rational_plus()... no
checking for struct RComplex... no
checking for rb_complex_raw()... yes
checking for rb_complex_real()... yes
checking for rb_complex_imag()... yes
checking for rb_complex_plus()... yes
checking for rb_complex_div()... yes
checking for rb_dbl_complex_new()... yes
creating Makefile
cd -
cd tmp/i386-linux-gnu/enumerable/statistics/extension/2.7.5
/usr/bin/gmake
compiling ../../../../../../ext/enumerable/statistics/extension/array_ext.c
compiling ../../../../../../ext/enumerable/statistics/extension/statistics.c
linking shared-object enumerable/statistics/extension.so
cp extension.so enumerable/statistics/extension.so
cd -
mkdir -p tmp/i386-linux-gnu/stage/lib/enumerable/statistics
install -c tmp/i386-linux-gnu/enumerable/statistics/extension/2.7.5/enumerable/statistics/extension.so lib/enumerable/statistics/extension.so
cp tmp/i386-linux-gnu/enumerable/statistics/extension/2.7.5/enumerable/statistics/extension.so tmp/i386-linux-gnu/stage/lib/enumerable/statistics/extension.so
/usr/bin/ruby2.7 -I/usr/share/rubygems-integration/all/gems/rspec-support-3.10.3/lib:/usr/share/rubygems-integration/all/gems/rspec-core-3.10.1/lib /usr/share/rubygems-integration/all/gems/rspec-core-3.10.1/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb
/root/enumerable-statistics/lib/enumerable/statistics/extension.so: warning: method redefined; discarding old sum
/root/enumerable-statistics/lib/enumerable/statistics/extension.so: warning: method redefined; discarding old sum
Run options: include {:focus=>true}
All examples were filtered out; ignoring {:focus=>true}
Randomized with seed 54641
1) Array#mean_variance for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09] is expected to eq [9090909.090909092, 909090909090909.4]
Failure/Error: it { is_expected.to eq([m, var]) }
expected: [9090909.090909092, 909090909090909.4]
got: [9090909.090909092, 909090909090909.0]
(compared using ==)
# ./spec/array_spec.rb:240:in `block (4 levels) in <top (required)>'
2) Array#stdev for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09] is expected to eq 30151134.457776368
Failure/Error: it { is_expected.to eq(x) }
expected: 30151134.457776368
got: 30151134.45777636
(compared using ==)
# ./spec/support/macros.rb:48:in `block in it_equals_with_type'
3) Array#mean_stdev for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09] is expected to eq [9090909.090909092, 30151134.457776368]
Failure/Error: it { is_expected.to eq([m, sd]) }
expected: [9090909.090909092, 30151134.457776368]
got: [9090909.090909092, 30151134.45777636]
(compared using ==)
# ./spec/array_spec.rb:335:in `block (4 levels) in <top (required)>'
4) Array#variance for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09] is expected to eq 909090909090909.4
Failure/Error: it { is_expected.to eq(x) }
expected: 909090909090909.4
got: 909090909090909.0
(compared using ==)
# ./spec/support/macros.rb:48:in `block in it_equals_with_type'
5) Array#mean for [1.0e-09, (100000000/1), 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09] is expected to eq 8333333.333333335
Failure/Error: it { is_expected.to eq(x) }
expected: 8333333.333333335
got: 8333333.333333333
(compared using ==)
# ./spec/support/macros.rb:48:in `block in it_equals_with_type'
6) Enumerable#mean_stdev for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09].each is expected to eq [9090909.090909092, 30151134.457776368]
Failure/Error: it { is_expected.to eq([m, sd]) }
expected: [9090909.090909092, 30151134.457776368]
got: [9090909.090909092, 30151134.45777636]
(compared using ==)
# ./spec/enum_spec.rb:422:in `block (4 levels) in <top (required)>'
7) Enumerable#variance for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09].each is expected to eq 909090909090909.4
Failure/Error: it { is_expected.to eq(x) }
expected: 909090909090909.4
got: 909090909090909.0
(compared using ==)
# ./spec/support/macros.rb:48:in `block in it_equals_with_type'
8) Enumerable#mean_variance for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09].each is expected to eq [9090909.090909092, 909090909090909.4]
Failure/Error: it { is_expected.to eq([m, var]) }
expected: [9090909.090909092, 909090909090909.4]
got: [9090909.090909092, 909090909090909.0]
(compared using ==)
# ./spec/enum_spec.rb:237:in `block (4 levels) in <top (required)>'
9) Enumerable#stdev for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09].each is expected to eq 30151134.457776368
Failure/Error: it { is_expected.to eq(x) }
expected: 30151134.457776368
got: 30151134.45777636
(compared using ==)
# ./spec/support/macros.rb:48:in `block in it_equals_with_type'
10) Enumerable#mean for [1.0e-09, (100000000/1), 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09].each is expected to eq 8333333.333333335
Failure/Error: it { is_expected.to eq(x) }
expected: 8333333.333333335
got: 8333333.333333333
(compared using ==)
# ./spec/support/macros.rb:48:in `block in it_equals_with_type'
11) Hash#sum for {:a=>(100000000/1), :b=>1.0e-09, :c=>1.0e-09, :d=>1.0e-09, :e=>1.0e-09, :f=>1.0e-09, :g=>1.0e-09, :h=>1.0e-09, :i=>1.0e-09, :j=>1.0e-09, :k=>1.0e-09} with conversion `(k, v) -> v` is expected to eq 100000000.00000001
Failure/Error: it { is_expected.to eq(x) }
expected: 100000000.00000001
got: 100000000.0
(compared using ==)
# ./spec/support/macros.rb:48:in `block in it_equals_with_type'
12) Hash#sum for {:a=>1.0e-09, :b=>(100000000/1), :c=>1.0e-09, :d=>1.0e-09, :e=>1.0e-09, :f=>1.0e-09, :g=>1.0e-09, :h=>1.0e-09, :i=>1.0e-09, :j=>1.0e-09, :k=>1.0e-09, :l=>1.0e-09} with conversion `(k, v) -> v` is expected to eq 100000000.00000001
Failure/Error: it { is_expected.to eq(x) }
expected: 100000000.00000001
got: 100000000.0
(compared using ==)
# ./spec/support/macros.rb:48:in `block in it_equals_with_type'
13) Hash#sum for {:a=>100000000, :b=>1.0e-09, :c=>1.0e-09, :d=>1.0e-09, :e=>1.0e-09, :f=>1.0e-09, :g=>1.0e-09, :h=>1.0e-09, :i=>1.0e-09, :j=>1.0e-09, :k=>1.0e-09} with conversion `(k, v) -> v` is expected to eq 100000000.00000001
Failure/Error: it { is_expected.to eq(x) }
expected: 100000000.00000001
got: 100000000.0
(compared using ==)
# ./spec/support/macros.rb:48:in `block in it_equals_with_type'
390/390 |========================================================================================== 100 ==========================================================================================>| Time: 00:00:00
Top 10 slowest examples (0.05823 seconds, 16.2% of total time):
Array#histogram with 10,000 normal random values closed: :right is expected to eq false
0.01379 seconds ./spec/histogram/array_spec.rb:179
Array#histogram with 10,000 normal random values default is expected to eq false
0.01376 seconds ./spec/histogram/array_spec.rb:164
Array#histogram with 10,000 normal random values nbins: 5 is expected to eq false
0.01348 seconds ./spec/histogram/array_spec.rb:194
Array#mean_variance for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09] is expected to eq [9090909.090909092, 909090909090909.4]
0.01055 seconds ./spec/array_spec.rb:240
Enumerable#sum for 1..0 with a conversion block does not call the conversion block
0.00194 seconds ./spec/range_spec.rb:19
Array#percentile for [1, nil, 3] is expected to match [(be nan), (be nan)]
0.00183 seconds ./spec/percentile/array_spec.rb:57
Array#percentile for [] is expected to raise ArgumentError
0.00108 seconds ./spec/percentile/array_spec.rb:10
Array#percentile for [1, NaN, 3] is expected to match [(be nan), (be nan)]
0.00101 seconds ./spec/percentile/array_spec.rb:50
Enumerable#sum for 3..5 is expected to be a kind of Integer
0.00041 seconds ./spec/support/macros.rb:47
Array#percentile for [1, 2, 3] is expected to eq [1.0, 1.5, 2.0, 2.5, 3.0]
0.00038 seconds ./spec/percentile/array_spec.rb:22
Top 10 slowest example groups:
Array#histogram
0.003 seconds average (0.04799 seconds / 16 examples) ./spec/histogram/array_spec.rb:4
Array
0.00139 seconds average (0.12517 seconds / 90 examples) ./spec/array_spec.rb:5
Array#percentile
0.00113 seconds average (0.00903 seconds / 8 examples) ./spec/percentile/array_spec.rb:3
Enumerable
0.00108 seconds average (0.09756 seconds / 90 examples) ./spec/enum_spec.rb:5
Array
0.00049 seconds average (0.01556 seconds / 32 examples) ./spec/value_counts_spec.rb:69
Hash
0.00047 seconds average (0.02012 seconds / 43 examples) ./spec/hash_spec.rb:5
Hash
0.00041 seconds average (0.01325 seconds / 32 examples) ./spec/value_counts_spec.rb:83
Enumerable
0.0004 seconds average (0.01254 seconds / 31 examples) ./spec/range_spec.rb:5
Enumerable
0.00035 seconds average (0.0113 seconds / 32 examples) ./spec/value_counts_spec.rb:101
Array#median
0.00031 seconds average (0.0049 seconds / 16 examples) ./spec/median/array_spec.rb:3
Finished in 0.36049 seconds (files took 0.83487 seconds to load)
390 examples, 13 failures
Failed examples:
rspec ./spec/array_spec.rb:240 # Array#mean_variance for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09] is expected to eq [9090909.090909092, 909090909090909.4]
rspec ./spec/array_spec.rb[1:5:7:2] # Array#stdev for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09] is expected to eq 30151134.457776368
rspec ./spec/array_spec.rb:335 # Array#mean_stdev for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09] is expected to eq [9090909.090909092, 30151134.457776368]
rspec ./spec/array_spec.rb[1:2:7:2] # Array#variance for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09] is expected to eq 909090909090909.4
rspec ./spec/array_spec.rb[1:1:8:2] # Array#mean for [1.0e-09, (100000000/1), 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09] is expected to eq 8333333.333333335
rspec ./spec/enum_spec.rb:422 # Enumerable#mean_stdev for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09].each is expected to eq [9090909.090909092, 30151134.457776368]
rspec ./spec/enum_spec.rb[1:2:7:2] # Enumerable#variance for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09].each is expected to eq 909090909090909.4
rspec ./spec/enum_spec.rb:237 # Enumerable#mean_variance for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09].each is expected to eq [9090909.090909092, 909090909090909.4]
rspec ./spec/enum_spec.rb[1:4:7:2] # Enumerable#stdev for [100000000, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09].each is expected to eq 30151134.457776368
rspec ./spec/enum_spec.rb[1:1:8:2] # Enumerable#mean for [1.0e-09, (100000000/1), 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09, 1.0e-09].each is expected to eq 8333333.333333335
rspec ./spec/hash_spec.rb[1:1:17:1:2] # Hash#sum for {:a=>(100000000/1), :b=>1.0e-09, :c=>1.0e-09, :d=>1.0e-09, :e=>1.0e-09, :f=>1.0e-09, :g=>1.0e-09, :h=>1.0e-09, :i=>1.0e-09, :j=>1.0e-09, :k=>1.0e-09} with conversion `(k, v) -> v` is expected to eq 100000000.00000001
rspec ./spec/hash_spec.rb[1:1:18:1:2] # Hash#sum for {:a=>1.0e-09, :b=>(100000000/1), :c=>1.0e-09, :d=>1.0e-09, :e=>1.0e-09, :f=>1.0e-09, :g=>1.0e-09, :h=>1.0e-09, :i=>1.0e-09, :j=>1.0e-09, :k=>1.0e-09, :l=>1.0e-09} with conversion `(k, v) -> v` is expected to eq 100000000.00000001
rspec ./spec/hash_spec.rb[1:1:16:1:2] # Hash#sum for {:a=>100000000, :b=>1.0e-09, :c=>1.0e-09, :d=>1.0e-09, :e=>1.0e-09, :f=>1.0e-09, :g=>1.0e-09, :h=>1.0e-09, :i=>1.0e-09, :j=>1.0e-09, :k=>1.0e-09} with conversion `(k, v) -> v` is expected to eq 100000000.00000001
Randomized with seed 54641
/usr/bin/ruby2.7 -I/usr/share/rubygems-integration/all/gems/rspec-support-3.10.3/lib:/usr/share/rubygems-integration/all/gems/rspec-core-3.10.1/lib /usr/share/rubygems-integration/all/gems/rspec-core-3.10.1/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb failed
from enumerable-statistics.
FWIW, the above was ran on a i386 lxc container under a amd64 system.
from enumerable-statistics.
Could you please tell me the full compiler option? I guess it can be seen by the following command:
ruby -rrbconfig -e "puts RbConfig::CONFIG['CFLAGS']"
from enumerable-statistics.
$ ruby -rrbconfig -e "puts RbConfig::CONFIG['CFLAGS']"
-g -O2 -ffile-prefix-map=/build/ruby2.7-I3v9IH/ruby2.7-2.7.5=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC
from enumerable-statistics.
@terceiro Could you please check the result of rake test
with Ruby that is built with -mfpmath=sse -msse2
options?
You can build Ruby with -mfpmath=sse -msse2
options by specifying optflags="-mfpmath=sse -msse2"
to configure
like below:
./configure optflags="-mfpmath=sse -msse2"
from enumerable-statistics.
@mrkn in Debian i386 binaries cannot be built unconditionally with SSE because hardware without it is still supported, so there is no point in me doing this test because the i386 ruby binary will not change. I understand you might not care about this use case, in that case the Debian package can just keep carrying the patch it's currently carrying, which is this:
From: Antonio Terceiro <[email protected]>
Date: Wed, 3 Nov 2021 08:42:28 -0300
Subject: spec: avoid testing floats for equality
Forwarded: https://github.com/mrkn/enumerable-statistics/issues/31
---
spec/support/macros.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/support/macros.rb b/spec/support/macros.rb
index 6d3dd6e..3ae99dd 100644
--- a/spec/support/macros.rb
+++ b/spec/support/macros.rb
@@ -45,7 +45,7 @@ module Enumerable
def it_equals_with_type(x, type)
it { is_expected.to be_an(type) }
- it { is_expected.to eq(x) }
+ it { is_expected.to be_within(0.0000001).of(x) }
end
def it_is_int_equal(n)
from enumerable-statistics.
@terceiro This patch is not appropriate for the tests you mentioned in this issue's description, especially for sum
methods.
The reason why is that the tests examine whether the precision compensation calculation is performed.
1) Hash#sum for {:a=>(100000000/1), :b=>1.0e-09, :c=>1.0e-09, :d=>1.0e-09, :e=>1.0e-09, :f=>1.0e-09, :g=>1.0e-09, :h=>1.0e-09, :i=>1.0e-09, :j=>1.0e-09, :k=>1.0e-09} with conversion `(k, v) -> v` is expected to eq 100000000.00000001
Failure/Error: it { is_expected.to eq(x) }
expected: 100000000.00000001
got: 100000000.0
(compared using ==)
# ./spec/support/macros.rb:48:in `block in it_equals_with_type'
For example in the above case, the purpose of this test examines the sum
method keeps the small number that is vanished by the round-off error. The test checks whether the effect of ten 1.0e-9
remains in the result of sum
method. The number 1.0e-9
is automatically selected by the following code:
large_number = 100_000_000
small_number = 1e-9
until (large_number + small_number) == large_number
small_number /= 10
end
This code finds the number that the addition with large_number
causes the round-off error. So the simple sum of large_number
and ten small_number
s by inject(:+)
equals to large_number
.
The test must check sum
method should produce the result that is different from the result by inject(:+)
.
from enumerable-statistics.
what do you suggest to do in this case? skip the failing tests on i386 without SSE?
from enumerable-statistics.
@terceiro In this case, skipping the failing tests is better than rewriting them with approximate comparing.
from enumerable-statistics.
ok, thanks for the feedback. For now I'm changing the Debian package to skip the entire test suite on i386, as it's a bit difficult to filter out only the ones that would fail.
from enumerable-statistics.
Related Issues (15)
- RubyDataScience HOT 2
- Support bins: option in value_counts
- bundle exec rake bench no longer works HOT 3
- Support JRuby
- Histogram may contain nil in weights HOT 1
- Where can I get more information about the edge detection algorithm? HOT 1
- Support Ruby 2.2 HOT 1
- Support MemoryView-exportable 1-D array objects
- value_counts
- histogram should accept :auto in nbins argument
- Add cumsum and cumprod
- histogram
- Add Windows CI
- Add pivot
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from enumerable-statistics.