intervals 0.3.63 → 0.4.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.txt CHANGED
@@ -191,6 +191,11 @@ Interval
191
191
  Analysis}[http://www.ebooks.dekker.com/eBookCover.asp?eBookID=0824758706&type=ISBN] -
192
192
  Second Edition, Revised and Expanded. John Dekker, Inc., 2003.
193
193
 
194
+ David Goldberg, {What Every Computer Scientist Should Know About
195
+ Floating-Point
196
+ Arithmetic}[http://docs-pdf.sun.com/800-7895/800-7895.pdf], ACM
197
+ Computing Surveys, vol. 23 (1991), pp. 5--48.
198
+
194
199
  == Author & License
195
200
 
196
201
  Copyright (c) 2006, Stefano Taschini.
data/VERSION.txt CHANGED
@@ -1 +1 @@
1
- 0.3.61:62M
1
+ 0.4.75
data/lib/fpu.rb CHANGED
@@ -27,6 +27,10 @@ end
27
27
 
28
28
  require File.dirname(__FILE__) + '/struct_float'
29
29
 
30
+ # This module provides the way of controlling the rounding mode of the
31
+ # floating-point unit (FPU) and also provides mathematical functions
32
+ # that round their result consistently with the specified rounding
33
+ # mode.
30
34
  module FPU
31
35
 
32
36
  #
@@ -81,207 +85,4 @@ module FPU
81
85
 
82
86
  end
83
87
 
84
- require 'test/unit'
85
-
86
- # Tests the FPU rounding modes.
87
- class FPU::TestRounding < Test::Unit::TestCase
88
- include FPU
89
-
90
- def setup
91
- @saved = rounding
92
- end
93
-
94
- def teardown
95
- self.rounding = @saved
96
- end
97
-
98
- # Nearest rounding of 1/3 is downwards.
99
- def test_third
100
- assert(FPU.down {1/3.0} == 1/3.0, "1/3 to -");
101
- assert(FPU.up {1/3.0} != 1/3.0, "1/3 to +");
102
- assert(FPU.down {-1/3.0} != -1/3.0, "-1/3 to -");
103
- assert(FPU.up {-1/3.0} == -1/3.0, "-1/3 to +");
104
- end
105
-
106
- # 1/4 is exact.
107
- def test_fourth
108
- assert(FPU.down {1/4.0} == 1/4.0, "1/4 to -");
109
- assert(FPU.up {1/4.0} == 1/4.0, "1/4 to +");
110
- assert(FPU.down {-1/4.0} == -1/4.0, "-1/4 to -");
111
- assert(FPU.up {-1/4.0} == -1/4.0, "-1/4 to +");
112
- end
113
-
114
- # Nearest rounding of 1/5 is upwards.
115
- def test_fifth
116
- assert(FPU.down {1/5.0} != 1/5.0, "1/5 to -");
117
- assert(FPU.up {1/5.0} == 1/5.0, "1/5 to +");
118
- assert(FPU.down {-1/5.0} == -1/5.0, "-1/5 to -");
119
- assert(FPU.up {-1/5.0} != -1/5.0, "-1/5 to +");
120
- end
121
-
122
- def test_platform
123
- modes = case (RUBY_PLATFORM)
124
- when /powerpc/ then [0,2,3]
125
- when /i[0-9]86/ then [0,0x0800,0x0400]
126
- when /sparc/ then [0,0x80000000, 0xC0000000]
127
- else flunk("Cannot be sure of the processor flags for platform "+RUBY_PLATFORM)
128
- end
129
- assert_equal(modes,
130
- [rounding, FPU.up { rounding }, FPU.down { rounding }])
131
- end
132
-
133
- def test_rounding_consts
134
- assert_equal(PlusRounding , FPU.up { FPU.rounding })
135
- assert_equal(MinusRounding , FPU.down { FPU.rounding })
136
- assert_equal(StandardRounding, rounding)
137
-
138
- tester = proc { |x| assert_equal(x, (self.rounding = x; FPU.rounding))}
139
- tester.call(PlusRounding);
140
- tester.call(MinusRounding);
141
- tester.call(StandardRounding);
142
- end
143
-
144
- def test_exception_safety
145
- assert_raise(ArgumentError){FPU.up {[2.0, 0/0.0].sort}}
146
- assert_equal(StandardRounding, rounding)
147
- assert_raise(ArgumentError){FPU.down {[2.0, 0/0.0].sort}}
148
- assert_equal(StandardRounding, rounding)
149
- end
150
-
151
- def test_power
152
- x = 1/3.0;
153
- # The cube of one third should depend on the rounding mode
154
- assert_operator(FPU.down{x*x*x}, :<, FPU.up{x*x*x})
155
- # But using the built-in power operator, usually it doesn't
156
- # assert_equal(FPU.down{x**3}, FPU.up{x**3})
157
- # So we define an integer power methods that does
158
- assert_operator(FPU.down{FPU.power(x, 3)}, :<, FPU.up{FPU.power(x, 3)})
159
-
160
- assert_equal(32, FPU.power(2, 5))
161
- assert_equal([FPU.down{x*x*x}, FPU.up{x*x*x}],[FPU.down{FPU.power(x, 3)},FPU.up{FPU.power(x, 3)}])
162
- assert_equal(1.25 ** 13, FPU.power(1.25, 13))
163
- assert_equal((-1.25) ** 17, FPU.power(-1.25, 17))
164
- assert_equal((-1.25) ** 18, FPU.power(-1.25, 18))
165
- (1..10).each {|i|
166
- assert_equal(2.0 ** i, FPU.power(2.0, i))
167
- }
168
-
169
- end
170
-
171
- end
172
-
173
- if !FPU.respond_to?(:exp_up)
174
- warn "***\n*** Module fpu is compiled without transcendetal functions\n***"
175
- else
176
- # Tests the correct-rounding transcendental functions, if they exist.
177
- class FPU::TestTranscendental < Test::Unit::TestCase
178
- require 'enumerator'
179
-
180
- def locate(name)
181
- ([File.dirname(__FILE__)] + $LOAD_PATH).
182
- map{|p| File.expand_path("../test/#{name}", File.expand_path(p))}.
183
- find(proc {raise LoadError, "Cannot locate #{name}"}) {|p|
184
- File.exist?(p)
185
- }
186
- end
187
-
188
- @@test_vectors_cache = {}
189
-
190
- def get_vectors (name)
191
- @@test_vectors_cache[name] ||= IO.readlines(locate(name)).map{|x|
192
- e1,m1,e2,m2 = x.chomp.split(' ').map{|y| y.to_i}
193
- [e1,m1,e2,m2,e2,m2 - 1].enum_slice(2).map{|e,m| Math::ldexp(m,e)}}
194
- end
195
-
196
- def test_easy
197
- a, b, c= [
198
- [-1, 1008, 2553927345288884],
199
- [1, 1022, 4503168880409012],
200
- [1, 1022, 4503168880409011]].map{|x| Struct::Float[*x].to_f}
201
- assert_equal(b, FPU.exp_up(a))
202
- assert_equal(c, FPU.exp_down(a))
203
-
204
- assert_equal(Infinity, FPU.exp_up(Infinity))
205
- assert_equal(Infinity, FPU.exp_down(Infinity))
206
- assert_equal(0, FPU.exp_up(-Infinity))
207
- assert_equal(0, FPU.exp_down(-Infinity))
208
-
209
- assert_equal(Infinity, FPU.log_up(Infinity))
210
- assert_equal(Infinity, FPU.log_down(Infinity))
211
- assert_equal(-Infinity, FPU.log_up(0))
212
- assert_equal(-Infinity, FPU.log_down(0))
213
-
214
- assert_equal(Math::PI, 2*FPU.atan_down(Infinity))
215
- assert_equal(Math::PI+2 ** -51, 2*FPU.atan_up(Infinity))
216
- assert_equal(-Math::PI, 2*FPU.atan_up(-Infinity))
217
- assert_equal(-Math::PI-2 ** -51, 2*FPU.atan_down(-Infinity))
218
- end
219
-
220
- def test_exp
221
- get_vectors("data_exp.txt").map{|x,y,z|
222
- assert_equal(y, FPU.exp_up(x))
223
- assert_equal(z, FPU.exp_down(x))
224
- }
225
- end
226
-
227
- def test_log
228
- get_vectors("data_log.txt").map{|x,y,z|
229
- assert_equal(y, FPU.log_up(x))
230
- assert_equal(z, FPU.log_down(x))
231
- }
232
- end
233
-
234
- def test_atan
235
- get_vectors("data_atan.txt").map{|x,y,z|
236
- assert_equal(y, FPU.atan_up(x))
237
- assert_equal(z, FPU.atan_down(x))
238
- }
239
- end
240
-
241
- def test_cos
242
- get_vectors("data_cos.txt").map{|x,y,z|
243
- assert_equal(y, FPU.cos_up(x))
244
- assert_equal(z, FPU.cos_down(x))
245
- }
246
- end
247
-
248
- def test_sin
249
- get_vectors("data_sin.txt").map{|x,y,z|
250
- assert_equal(y, FPU.sin_up(x))
251
- assert_equal(z, FPU.sin_down(x))
252
- }
253
- end
254
-
255
- def test_tan
256
- get_vectors("data_tan.txt").map{|x,y,z|
257
- assert_equal(y, FPU.tan_up(x))
258
- assert_equal(z, FPU.tan_down(x))
259
- }
260
- end
261
-
262
- def test_cosh
263
- get_vectors("data_cosh.txt").map{|x,y,z|
264
- assert_equal(y, FPU.cosh_up(x))
265
- assert_equal(z, FPU.cosh_down(x))
266
- }
267
- end
268
-
269
- def test_sinh
270
- get_vectors("data_sinh.txt").map{|x,y,z|
271
- assert_equal(y, FPU.sinh_up(x))
272
- assert_equal(z, FPU.sinh_down(x))
273
- }
274
- end
275
-
276
- # It can happen, depending on the implementation, that Math::sinh is broken
277
- def broken_math #:nodoc:
278
- x = -8218111829489689 * 2.0 **(-67)
279
- y = -8218111833737307 * 2.0 **(-67)
280
- assert_equal(y, FPU.sinh_up(x))
281
- z = Math::sinh(x);
282
- assert(z <= y, [FPU.split(x), FPU.split(z), FPU.split(y)].inspect)
283
- end
284
-
285
- end end
286
-
287
- Test::Unit.run = (__FILE__ != $0)
88
+ require File.dirname(__FILE__) + '/../test/test_fpu.rb' if __FILE__ == $0
data/lib/interval.rb CHANGED
@@ -27,6 +27,10 @@ end
27
27
  class Interval
28
28
  include Enumerable
29
29
 
30
+ # Exception class for failed preconditions on construction arguments.
31
+ class ConstructionError < ArgumentError
32
+ end
33
+
30
34
  # Create a closed (multi-)interval with the given numerical extrema.
31
35
  #
32
36
  # Interval[3] # In mathematical notation: [3,3]
@@ -38,25 +42,34 @@ class Interval
38
42
  # Interval[[1,3],[2,4]] # => Interval[1, 4]
39
43
  #
40
44
  def Interval.[](*array)
41
- make(
45
+ union(*
42
46
  if array.empty?
43
47
  []
44
- elsif array.first.kind_of?(Numeric)
45
- [Simple[*array]]
48
+ elsif array.first.kind_of?(Array)
49
+ array.select{|x| !x.empty?}.map { |x| Simple.new(*x) }
46
50
  else
47
- array.select{|x| !x.empty?}.map { |x| Simple[*x] }
51
+ [Simple.new(*array)]
48
52
  end
49
53
  )
54
+ rescue StandardError
55
+ unless
56
+ array.all?{|x| Numeric === x} && array.size <= 2 ||
57
+ array.all?{|x| Array === x && x.size <= 2 && x.all?{|c| Numeric === c}}
58
+ raise ConstructionError,
59
+ "An interval can only be constructed either from at most two numbers or from a " \
60
+ "sequence of arrays of at most two numbers: #{array.inspect}"
61
+ end
62
+ raise
50
63
  end
51
64
 
52
- # Create a closed (multi-)interval from a set of simple intervals.
65
+ # Create the union of an array of intervals.
53
66
  #
54
- # Interval.make(Interval[1,2], Interval[3,4])
67
+ # Interval.union(Interval[1,2], Interval[3,4])
55
68
  # # => Interval[[1, 2], [3, 4]]
56
69
  #
57
- def Interval.make(comps)
70
+ def Interval.union(*array)
58
71
  l = []
59
- comps.sort_by{|x| x.inf}.each{|x|
72
+ array.map{|x| x.components}.flatten.sort_by{|x| x.inf}.each{|x|
60
73
  if x.sup < x.inf
61
74
  # skip it
62
75
  elsif l.empty? || x.inf > l.last.sup
@@ -72,6 +85,20 @@ class Interval
72
85
  end
73
86
  end
74
87
 
88
+ # Add all the arguments using Kahan's summation formula, which
89
+ # provides sharper results than conventional sum.
90
+ def Interval.sum(*array)
91
+ Interval.union *array.inject([[Interval[0],Interval[0]]]) {|sc, xx|
92
+ sc.inject([]){|a1,(s,c)|
93
+ xx.inject(a1){|a2,x|
94
+ y = x.dsub(c)
95
+ t = s + y
96
+ a2 + [[t, t.dsub(s).dsub(y)]]
97
+ }
98
+ }
99
+ }.transpose.first
100
+ end
101
+
75
102
  # Returns a list of the parameters that can be used to reconstruct the
76
103
  # interval.
77
104
  #
@@ -222,7 +249,7 @@ class Interval
222
249
  ## Implement unary operations
223
250
  [:inverse, :exp, :log, :atan, :cos, :sin, :tan, :cosh, :sinh].each {|op|
224
251
  define_method(op) {
225
- Interval.make(map{|x| x.send(op).components}.flatten)
252
+ Interval.union(*map{|x| x.send(op)})
226
253
  }
227
254
  }
228
255
 
@@ -231,7 +258,7 @@ class Interval
231
258
  # Interval[-2,2]**2 # => Interval[0, 4]
232
259
  #
233
260
  def ** (n)
234
- Interval.make(map{|x| (x**n).components}.flatten)
261
+ Interval.union(*map{|x| (x**n)})
235
262
  end
236
263
 
237
264
  # Sum of intervals.
@@ -282,7 +309,7 @@ class Interval
282
309
  ## Implement binary operations: Sum (+), Multiplication (*) and Intersection (&)
283
310
  [[:+, :add], [:*, :multiply], [:&, :intersect]].each {|op, meth|
284
311
  define_method(op) {|other|
285
- Interval.make(other.to_interval.map {|y| self.map {|x| x.send(meth,y) } }.flatten)
312
+ Interval.union(*other.to_interval.map {|y| self.map {|x| x.send(meth,y) } }.flatten)
286
313
  }
287
314
  }
288
315
 
@@ -302,7 +329,7 @@ class Interval
302
329
  # # => Interval[1, 4]
303
330
  #
304
331
  def | (other)
305
- Interval.make(other.to_interval.components + self.components)
332
+ Interval.union(other.to_interval, self)
306
333
  end
307
334
 
308
335
  # True if the interval has no elements.
@@ -334,10 +361,10 @@ class Interval
334
361
  end
335
362
  end
336
363
 
337
- @@newtonOpts = {
364
+ # The default options for Interval#newton.
365
+ NewtonOptions = {
338
366
  :maxIterations => 100,
339
- :verbose => false
340
- }
367
+ :verbose => false }
341
368
 
342
369
  # Solve a non-linear equation using the Newton-Raphson method,
343
370
  # finding all solutions in a in interval.
@@ -354,7 +381,7 @@ class Interval
354
381
  # a sharp result showing the three roots -1, 0 and +1.
355
382
  #
356
383
  def newton(f, fp, opts = {})
357
- effectiveOpts = @@newtonOpts.dup.update(opts)
384
+ effectiveOpts = NewtonOptions.dup.update(opts)
358
385
  verbose = effectiveOpts[:verbose]
359
386
  puts "Starting on #{self}" if verbose
360
387
  step = proc {|w,ww| (w - f.call(Interval[w]) / fp.call(ww) ) & ww}
@@ -428,21 +455,14 @@ class Interval::Simple < Interval
428
455
  [self]
429
456
  end
430
457
 
431
- # Constructs a simple interval with given extrema.
432
- #
433
- # Interval::Simple[1] # => Interval[1]
434
- # Interval::Simple[1,2] # => Interval[1,2]
435
- #
436
- def Simple.[](a, b = a)
437
- new(a, b)
438
- end
439
-
440
458
  # Constructs a simple interval, with given lower and upper bounds.
441
459
  #
442
- # Interval::Simple.new(1,1) # => Interval[1]
460
+ # Interval::Simple.new(1) # => Interval[1]
443
461
  # Interval::Simple.new(1,2) # => Interval[1,2]
444
462
  #
445
- def initialize (a, b)
463
+ def initialize (a, b = a)
464
+ raise ArgumentError, "Extrema must be numeric: #{[a,b].uniq.inspect}" unless
465
+ Numeric === a && Numeric === b
446
466
  if (a.respond_to?(:nan?) && a.nan? ) || (b.respond_to?(:nan?) && b.nan?)
447
467
  @inf, @sup = -Infinity, Infinity
448
468
  else
@@ -515,9 +535,9 @@ class Interval::Simple < Interval
515
535
  # Interval[1,2] + Interval[2]
516
536
  # # => Interval[3,4]
517
537
  def dsub(other)
518
- Interval[
538
+ self.class.new(
519
539
  FPU.down{inf - other.inf},
520
- FPU.up {sup - other.sup}]
540
+ FPU.up {sup - other.sup})
521
541
  end
522
542
 
523
543
  # Used to implement Interval's multiplicative operator (\*).
@@ -529,6 +549,9 @@ class Interval::Simple < Interval
529
549
  FPU.up {
530
550
  [inf * other.inf, inf * other.sup,
531
551
  sup * other.inf, sup * other.sup]}.max)
552
+ # min and max fail if any of the products is a NaN, which can only
553
+ # be generated by 0 * Infinity. In this case, the result is the
554
+ # whole R-star.
532
555
  rescue ArgumentError
533
556
  self.class.new(-Infinity, Infinity)
534
557
  end
@@ -708,6 +731,12 @@ class Range
708
731
  else
709
732
  last
710
733
  end]
734
+ rescue NoMethodError
735
+ if exclude_end? && !last.respond_to?(:succ)
736
+ raise Interval::ConstructionError,
737
+ "A three-dot range with non-discrete upper bound cannot be made into a closed interval"
738
+ end
739
+ raise
711
740
  end
712
741
 
713
742
  end
@@ -722,483 +751,4 @@ class Interval
722
751
 
723
752
  end
724
753
 
725
- require 'test/unit'
726
-
727
- # Assertions to be used when testing intervals.
728
- module Interval::Assertions
729
-
730
- def assert_sharp(x)
731
- assert(x.sharp?, x.inspect + " should be sharp.")
732
- assert((-x).sharp?, (-x).inspect + " should be sharp.")
733
- end
734
-
735
- # Assert that an interval is not sharp.
736
- def assert_fuzzy(x)
737
- assert(!x.sharp?, x.inspect + " should not be sharp.")
738
- assert(!(-x).sharp?, (-x).inspect + " should not be sharp.")
739
- end
740
-
741
- # Assert that +s+ is a solution to +f+ == 0. Unless the +weak+ flag is set,
742
- # assert also that +s+ == +expected+.
743
- # If the +weak+ flag is set, assert that +s+ includes +expected+.
744
- def assert_solution(s,f,expected, weak = nil)
745
- res = s.map{|c| f.call(c)}.inject{|a,c| a|c}
746
- # Did something spectacarly unexpected happen?
747
- assert(res.simple?, res)
748
- # Is it a solution?
749
- assert_include(res, 0)
750
- # Is it minimal?
751
- assert(s.all? {|x| x.extrema.all? {|y| f.call(Interval[y]).include?(0)}}, s.inspect +
752
- " is non minmal")
753
- # Is it the expected solution?
754
- if weak
755
- # check the granularity
756
- assert_equal(expected.components.size, s.components.size, [expected,s].inspect)
757
- # check for inclusion
758
- assert_subset(expected, s)
759
- else
760
- # check for equality
761
- assert_equal(expected,s)
762
- end
763
- end
764
-
765
- # Assert that the interval +i+ includes +x+.
766
- def assert_include(i, x)
767
- assert(i.include?(x), i.inspect + " should include " + x.inspect)
768
- end
769
-
770
- # Assert that the interval +i+ does not include +x+.
771
- def assert_outside(i, x)
772
- assert(!i.include?(x), i.inspect + " should not include " + x.inspect)
773
- end
774
-
775
- # Assert that +x+ is a subset of +y+.
776
- def assert_subset(x,y)
777
- assert(x == x & y, x.inspect + " should be a subset of " + y.inspect)
778
- end
779
-
780
- end
781
-
782
- # Tests Interval fundamentals: construction, equality and inspection.
783
- class Interval::TestFundamentals < Test::Unit::TestCase
784
-
785
- def test_constructor_and_equality
786
- tester = proc {|i,ex,klass|
787
- assert_equal(klass, i.class)
788
- assert_equal(ex, i.construction)
789
- assert_equal(i, Interval[*i.construction])
790
- }
791
-
792
- tester.call Interval[1], [1], Interval::Simple
793
- tester.call Interval[1,2], [1,2], Interval::Simple
794
- tester.call Interval[[1,2],[3,4]], [[1,2],[3,4]], Interval::Multiple
795
- tester.call Interval[[1],[2]], [[1],[2]], Interval::Multiple
796
- tester.call Interval[[1]], [1], Interval::Simple
797
- tester.call Interval[2,0/0.0], [-Infinity,+Infinity], Interval::Simple
798
- tester.call Interval[0/0.0,9], [-Infinity,+Infinity], Interval::Simple
799
- tester.call Interval[[1,3],[4,6],[2,5],[9,9]], [[1,6],[9]], Interval::Multiple
800
- end
801
-
802
- def test_construction_failure
803
- assert_raise(NoMethodError) { Interval[1,[2,3]] }
804
- assert_raise(ArgumentError) { Interval[1,2,3] }
805
- assert_raise(NoMethodError) { Interval[1,[2,3]] }
806
- assert_raise(NoMethodError) { Interval[[1],2] }
807
- end
808
-
809
- def test_inequality
810
- assert_not_equal(Interval[1,2], Interval[1,3])
811
- assert_not_equal(Interval[1,2], Interval[0,2])
812
- assert_not_equal(Interval[1,2], Interval[0,3])
813
- assert_not_equal(Interval[1,2], 3)
814
- assert_not_equal(Interval[[1,2],[3,4]], Interval[[1,0],[3,4]])
815
- end
816
-
817
- def test_inspect_and_to_s
818
- tester = proc {|s|
819
- i = eval(s)
820
- assert_equal(s,i.inspect)
821
- assert_equal(s,i.to_s)
822
- }
823
- tester.call "Interval[1]"
824
- tester.call "Interval[1, 2]"
825
- tester.call "Interval[[1, 2], [3, 4]]"
826
- tester.call "Interval[[1, 2], [4], [5, 6], [Infinity]]"
827
- tester.call "Interval[1, 2]"
828
- end
829
-
830
- end
831
-
832
- # Tests the arithmetic of Interval::Simple.
833
- class Interval::TestSimpleArithmetic < Test::Unit::TestCase
834
-
835
- def test_plus
836
- assert_equal(Interval[-Infinity,+Infinity], Interval[-Infinity] + Interval[Infinity])
837
- assert_equal(Interval[4,6], Interval[1,2] + Interval[3,4])
838
- assert_equal(Interval[3,Infinity], Interval[1,Infinity]+Interval[2])
839
- assert_equal(Interval[-Infinity,+Infinity],Interval[-Infinity,-1] + Interval[2,+Infinity])
840
- assert_equal(Interval[-Infinity,+Infinity],Interval[-Infinity] + Interval[8,+Infinity])
841
- end
842
-
843
- def test_minus
844
- assert_equal(Interval[-2,-1], -Interval[1,2])
845
- end
846
-
847
- def test_dsub
848
- assert_equal(Interval[2], Interval[3,4].dsub(Interval[1,2]))
849
- assert_equal(Interval[3,4], Interval[4,6].dsub(Interval[1,2]))
850
- assert_equal(Interval[], Interval[3,4].dsub(Interval[0,2]))
851
-
852
- end
853
-
854
- def test_times
855
- assert_equal(Interval[-Infinity,+Infinity],Interval[Infinity] * Interval[0])
856
- assert_equal(Interval[+Infinity],Interval[Infinity] * Interval[3])
857
- assert_equal(Interval[-8,+10], Interval[1,2] * Interval[-4,5])
858
- assert_equal(Interval[3,8], Interval[1,2] * Interval[3,4])
859
- assert_equal(Interval[-Infinity,+Infinity],Interval[0,1] * Interval[2,Infinity])
860
- assert_equal(Interval[2, Infinity], Interval[-Infinity,-2] * Interval[-Infinity,-1])
861
- end
862
-
863
- def test_inverse
864
- assert_equal(Interval[0.5,1],Interval[1,2].inverse)
865
- assert_equal(Interval[-1,-0.5],(-Interval[1,2]).inverse)
866
- assert_equal(Interval[[-Infinity,-1],[0.5,+Infinity]],Interval[-1,2].inverse)
867
- assert_equal(Interval[[-Infinity],[1,+Infinity]],Interval[0,1].inverse)
868
- end
869
-
870
- def test_power
871
- assert_equal((-Interval[1,2]).inverse, (-Interval[1,2]) ** -1)
872
- assert_equal(Interval[0,4], Interval[-1,2]**2)
873
- assert_equal(Interval[-27,8], Interval[-3,2]**3)
874
-
875
- assert_equal(
876
- Interval[FPU.down{(1/3.0)*(1/3.0)},FPU.up{(1/3.0)*(1/3.0)}],
877
- (Interval[1]/3.0) ** 2)
878
-
879
- assert_equal(
880
- Interval[
881
- FPU.down{(1/3.0)*(1/3.0)*(1/3.0)},
882
- FPU.up{(1/3.0)*(1/3.0)*(1/3.0)}],
883
- (Interval[1]/3.0) ** 3)
884
- end
885
-
886
- end
887
-
888
- # Tests other methods of Interval::Simple.
889
- class Interval::TestSimpleMethods < Test::Unit::TestCase
890
-
891
- def test_midpoint
892
- assert_equal(1.5,Interval[1,2].midpoint)
893
- assert_raise(NoMethodError){ Interval[[1,2],[3,4]].midpoint }
894
- end
895
-
896
- def test_width
897
- assert_equal(1, Interval[1,2].width)
898
- assert_equal(1, Interval[1,2].width)
899
- tester = proc{|x|
900
- assert_equal(
901
- 2.0 ** (-(Math.log(x)/Math.log(2)).ceil - 52),
902
- (1/Interval[x]).width)
903
- }
904
- tester.call(3.0)
905
- tester.call(5.0)
906
- tester.call(119.0)
907
- tester.call(34e-4)
908
- end
909
-
910
- end
911
-
912
- # Tests Interval algebra.
913
- class Interval::TestAlgebra < Test::Unit::TestCase
914
-
915
- def test_union
916
- assert_equal(Interval[[1, 6], [9, 9]], Interval[[1, 3],[4, 6]] | Interval[[2, 5], [9,9]])
917
- end
918
-
919
- def test_plus
920
- tester = proc{|x,y,sum|
921
- assert_equal(sum,x+y)
922
- assert_equal(sum,y+x)
923
- }
924
- tester.call(Interval[[1,2],[10,Infinity]], Interval[[1,9],[-2,-1]], Interval[[-1,1],[2,Infinity]])
925
- tester.call(Interval[1,9], Interval[[1,2],[10,Infinity]], Interval[2,Infinity])
926
- tester.call(Interval[1,2], 2, Interval[3,4])
927
- end
928
-
929
- def test_intersection
930
- tester = proc{|x,y,z|
931
- assert_equal(z, x & y)
932
- assert_equal(z, y & x)
933
- }
934
- tester.call(Interval[1,2], Interval[0,3], Interval[1,2])
935
- tester.call(Interval[1.1,1.9], Interval[1.3,2.5], Interval[1.3, 1.9])
936
- tester.call(Interval[1.1,1.9], Interval[0.3,0.7], Interval[])
937
- end
938
-
939
- def test_inverse
940
- assert_equal(Interval[[-Infinity, -2.0],[0.0, Infinity]],Interval[[-0.5,0.5],[0.2,Infinity]].inverse)
941
- end
942
-
943
- def test_minus
944
- assert_equal(Interval[[-4,-3],[-2,-1]], -Interval[[1,2],[3,4]])
945
- end
946
-
947
- def test_times
948
- tester = proc{|x,y,z|
949
- assert_equal(z,x*y)
950
- assert_equal(z,y*x)
951
- }
952
- tester.call(Interval[[1, 2], [3, 4]], Interval[0.5, 2], Interval[0.5,8])
953
- tester.call(Interval[1,2], 2, Interval[2,4])
954
- end
955
-
956
- def test_division
957
- assert_equal(Interval[-Infinity, Infinity], Interval[0,1]/Interval[0,1])
958
- assert_equal(Interval[0.5], Interval[1]/2)
959
- end
960
-
961
- def test_power
962
- assert_equal(Interval[-1,2], (Interval[-1,2]**-1)**-1)
963
- end
964
-
965
- end
966
-
967
- #Tests other Interval methods.
968
- class Interval::TestMethods < Test::Unit::TestCase
969
- include Interval::Assertions
970
-
971
- def test_include?
972
- assert_include(Interval[1,2], 1.5)
973
- assert_include(Interval[1,2], 1)
974
- assert_include(Interval[1,2], 2)
975
- assert_outside(Interval[1,2], 0)
976
- assert_outside(Interval[1,2], 4)
977
- end
978
-
979
- def test_simple?
980
- assert(Interval[1,2].simple?)
981
- assert(!Interval[[1,2],[3,4]].simple?)
982
- end
983
-
984
- def test_empty?
985
- assert(!Interval[1,2].empty?)
986
- assert(!Interval[[1,2],[4,3]].empty?)
987
- assert(Interval[].empty?)
988
- end
989
-
990
- def test_sharp?
991
- assert_sharp(Interval[5,5])
992
- assert_sharp(Interval[[1],[2]])
993
- assert_fuzzy(Interval[[1],[2,3]])
994
- assert_fuzzy(Interval[5,6])
995
- assert_fuzzy(Interval[1.1,1.2])
996
- assert_fuzzy(Interval[Struct::Float[-1,0,1].to_f,Struct::Float[+1,0,1].to_f])
997
- assert_sharp(Interval[Struct::Float[1,1022,2**52-1].to_f,1])
998
- assert_sharp(Interval[Struct::Float[1,1029,2**52-1].to_f,128])
999
- assert_sharp(Interval[-0.0,0.0])
1000
- assert_sharp(Interval[0.0,Struct::Float[1,0,1].to_f])
1001
- assert_sharp(Interval[6369051672525772, 6369051672525773] * 2.0 ** -52)
1002
- assert_sharp(Interval[6369051672525772, 6369051672525772] * 2.0 ** -52)
1003
- assert_fuzzy(Interval[6369051672525771, 6369051672525773] * 2.0 ** -52)
1004
- assert_fuzzy(Interval[6369051672525771, 6369051672525785] * 2.0 ** -52)
1005
- end
1006
-
1007
- def test_hull
1008
- assert_equal(Interval[1,4], Interval[[1,2],[3,4]].hull)
1009
- assert_equal(Interval[1,4], Interval[1,4].hull)
1010
- assert_equal(Interval[], Interval[].hull)
1011
- end
1012
-
1013
- def test_conversion_from_range
1014
- assert_equal(Interval[1.2, 5.3], (1.2 .. 5.3).to_interval)
1015
- assert_equal(Interval[1, 4], (1 .. 4).to_interval)
1016
- assert_equal(Interval[1, 3], (1 ... 4).to_interval)
1017
- assert_raise(NoMethodError){ (1 ... 3.1).to_interval }
1018
- end
1019
-
1020
- end
1021
-
1022
- # Tests the Interval-based non-linear solver.
1023
- class Interval::TestNewton < Test::Unit::TestCase
1024
- include Interval::Assertions
1025
-
1026
- def test_sqrt2
1027
- f, fp = proc {|x| x**2 - 2}, proc {|x| 2*x}
1028
- s = Math::sqrt(2)
1029
- assert_equal(6369051672525773 * 2.0 **-52, s)
1030
- assert_equal(Interval[s], Interval[0.1,5.0].newton(f, fp))
1031
- assert_equal(Interval[], Interval[2.0,5.0].newton(f,fp))
1032
- assert_equal(Interval[s], Interval[-1.0,10.0].newton(f,fp))
1033
- assert_equal(Interval[-s], Interval[-5.0,0].newton(f,fp))
1034
- assert_equal(Interval[[-s],[s]], Interval[-5.0,5.0].newton(f,fp))
1035
- end
1036
-
1037
- def test_cubic_1
1038
- f, fp = proc {|x| x**3 + x - 10}, proc {|x| 3*x**2 + 1}
1039
- s = Interval[-1,5].newton(f,fp)
1040
- assert_solution(s, f, Interval[2])
1041
- end
1042
-
1043
- def test_cubic_2
1044
- f, fp = proc {|x| x**3 + x - 15}, proc {|x| 3*x**2 + 1}
1045
- s = Interval[-1.0,5.0].newton(f,fp)
1046
- assert_solution(s, f, Interval[5249383869325654 * 2.0 ** -51])
1047
- end
1048
-
1049
- def test_cubic_3
1050
- f, fp = proc {|x| x * (x ** 2 - 1)}, proc {|x| 3*x**2 - 1}
1051
- s = Interval[-5.0,5.0].newton(f,fp)
1052
- assert_solution(s, f, Interval[[-1],[0],[1]])
1053
- end
1054
-
1055
- def test_dennis_schnabel
1056
- f1 = proc {|x| (((x-12) * x + 47 ) * x - 60 )* x}
1057
- f2 = proc {|x| f1.call(x) + 24 }
1058
- f3 = proc {|x| f1.call(x) + 24.1 }
1059
- fp = proc {|x| ((4 * x - 12*3) * x + 47*2) * x - 60}
1060
-
1061
- assert_solution(Interval[-1e2,1e2].newton(f1,fp), f1, Interval[[0],[3],[4],[5]],:weak)
1062
- assert_solution(Interval[-1e2,1e2].newton(f2,fp), f2, Interval[[0.888305779071752],[1]], :weak)
1063
- assert_equal(Interval[], Interval[-1e2,1e2].newton(f3,fp))
1064
- end
1065
-
1066
- if FPU.respond_to?(:exp_up)
1067
- def test_exp
1068
- f, fp = proc{|x| x.exp + x}, proc {|x| x.exp + 1}
1069
- z0 = Interval[-1e2,1e2].newton(f,fp)
1070
- assert_solution(z0, f, Interval[-0.56714329040978384])
1071
-
1072
- f, fp = proc{|x| x*(-x).exp + 1}, proc {|x| (1-x)*(-x).exp}
1073
- z1 = Interval[-1e2,1e2].newton(f,fp)
1074
- assert_solution(z0, f, z0, :weak)
1075
- assert_sharp(z1)
1076
- end end
1077
-
1078
- if FPU.respond_to?(:exp_up)
1079
- def test_trig
1080
- f = proc{|x| (x*Interval::PI/3.0).cos() -0.5}
1081
- fp = proc{|x| -(x*Interval::PI/3).sin() * Interval::PI/3}
1082
- s = Interval[-10.0,10.0].newton(f, fp)
1083
- assert_solution(s, f, Interval[[-7], [-5], [-1], [1], [5], [7]], :weak)
1084
- end end
1085
-
1086
- end
1087
-
1088
- if FPU.respond_to?(:exp_up)
1089
- # Tests Interval transcendental functions.
1090
- class Interval::TestTranscendental < Test::Unit::TestCase
1091
- include Interval::Assertions
1092
-
1093
- def test_exp
1094
- assert_equal(Interval::E, Interval[1].exp)
1095
- assert_equal(Interval[1,Interval::E.sup], Interval[0,1].exp)
1096
- assert_equal(Interval[Interval::E.inf, Infinity], Interval[1,Infinity].exp)
1097
- assert_equal(Interval[0], Interval[-Infinity].exp)
1098
- assert_equal(Interval[[0, 1], [Math::E, Infinity]], Interval[[-Infinity,0],[1,Infinity]].exp)
1099
- end
1100
-
1101
- def test_log
1102
- assert_equal(Interval[-Infinity, 0], Interval[-1,+1].log)
1103
- assert_equal(Interval[0], Interval[1].log)
1104
- assert_equal(Interval[], Interval[-2,-1].log)
1105
- assert_equal(Interval[-Infinity], Interval[-2,0].log)
1106
- assert_equal(Interval[-Infinity,0], Interval[0,1].log)
1107
- assert_include(Interval::E.log, 1)
1108
- assert_equal(3 * 2 ** -53, Interval[1].exp.log.width)
1109
- end
1110
-
1111
- def test_atan
1112
- assert_equal(Interval::PI, 4 * Interval[1].atan)
1113
- assert_equal(Interval[-Interval::PI.sup, Interval::PI.sup], 2 * Interval[-Infinity,Infinity].atan)
1114
- assert_equal(Interval[0], Interval[0].atan)
1115
- end
1116
-
1117
- def test_cosh
1118
- assert_sharp(Interval[1].cosh)
1119
- assert_equal(Interval[1], Interval[0].cosh)
1120
- assert_equal((Interval[1].cosh | Interval[3].cosh).hull, Interval[1,3].cosh)
1121
- assert_equal(Interval[1,3].cosh, Interval[-3,-1].cosh)
1122
- assert_equal((Interval[0] | Interval[3].cosh).hull, Interval[-1,3].cosh)
1123
- assert_equal(Interval[-1,3].cosh, Interval[-3,1].cosh)
1124
- assert_equal(Interval[0, Infinity], Interval[-Infinity,Infinity].cosh)
1125
- end
1126
-
1127
- def test_sinh
1128
- assert_sharp(Interval[1].sinh)
1129
- assert_equal(Interval[0], Interval[0].sinh)
1130
- assert_equal((Interval[-1].sinh | Interval[3].sinh).hull, Interval[-1,3].sinh)
1131
- assert_equal(Interval[-Infinity, Infinity], Interval[-Infinity,Infinity].sinh)
1132
- end
1133
-
1134
- def test_cos
1135
- assert_equal(Interval[-1,-1 + 2 ** -53], Interval::PI.cos)
1136
- assert_equal(Interval[1 - 2 ** -53, 1], (2*Interval::PI).cos)
1137
- assert_equal(Interval[-1,1], Interval[Infinity].cos)
1138
- assert_equal(Interval[-1,1], Interval[-Infinity].cos)
1139
- onehalf = (Interval::PI/3).cos
1140
- assert_include(onehalf, 0.5)
1141
- assert_equal(Interval[onehalf.inf,1], (-Interval::PI/4 | Interval::PI/3).hull.cos)
1142
- minusonehalf = (2*Interval::PI/3).cos
1143
- assert_include(minusonehalf, -0.5)
1144
- assert_equal(Interval[-1,minusonehalf.sup], (5*Interval::PI/4 | 2*Interval::PI/3).hull.cos)
1145
- assert_equal((minusonehalf | onehalf).hull, ((Interval::PI | 2*Interval::PI).hull/3).cos)
1146
- full = (5 * Interval::PI/3 | 3.5 * Interval::PI).hull
1147
- assert_equal(Interval[-1,1], full.cos)
1148
- assert_equal(Interval[-1,1], (full + 2 * Interval::PI).cos)
1149
- assert_equal(Interval[-1,1], (full + 4 * Interval::PI).cos)
1150
- assert_equal(Interval[-1,1], (full + 6 * Interval::PI).cos)
1151
- assert_equal(Interval[-1,1], (full + 8 * Interval::PI).cos)
1152
- assert_equal(Interval[-1,1], (full - 2 * Interval::PI).cos)
1153
- assert_equal(Interval[-1,1], (full - 4 * Interval::PI).cos)
1154
- assert_equal(Interval[-1,1], (full - 6 * Interval::PI).cos)
1155
- assert_equal(Interval[-1,1], (full - 8 * Interval::PI).cos)
1156
- end
1157
-
1158
- def test_sin
1159
- assert_equal(Interval[-1,-1 + 2 ** -53], (3*Interval::PI/2).sin)
1160
- assert_equal(Interval[1 - 2 ** -53, 1], (Interval::PI/2).sin)
1161
- assert_equal(Interval[-1,1], Interval[Infinity].sin)
1162
- assert_equal(Interval[-1,1], Interval[-Infinity].sin)
1163
- onehalf = (Interval::PI/6).sin
1164
- assert_include(onehalf, 0.5)
1165
- assert_equal(Interval[onehalf.inf,1], (3 * Interval::PI/4 | Interval::PI/6).hull.sin)
1166
- minusonehalf = (7*Interval::PI/6).sin
1167
- assert_include(minusonehalf, -0.5)
1168
- assert_equal(Interval[-1,minusonehalf.sup], (7*Interval::PI/4 | 7*Interval::PI/6).hull.sin)
1169
- assert_equal((-onehalf | onehalf).hull, ((Interval::PI | -Interval::PI).hull/6.0).sin)
1170
- full = ((5 * Interval::PI/3 | 3.5 * Interval::PI) + Interval::PI/2).hull
1171
- assert_equal(Interval[-1,1], full.sin)
1172
- assert_equal(Interval[-1,1], (full + 2 * Interval::PI).cos)
1173
- assert_equal(Interval[-1,1], (full + 4 * Interval::PI).cos)
1174
- assert_equal(Interval[-1,1], (full + 6 * Interval::PI).cos)
1175
- assert_equal(Interval[-1,1], (full + 8 * Interval::PI).cos)
1176
- assert_equal(Interval[-1,1], (full - 2 * Interval::PI).cos)
1177
- assert_equal(Interval[-1,1], (full - 4 * Interval::PI).cos)
1178
- assert_equal(Interval[-1,1], (full - 6 * Interval::PI).cos)
1179
- assert_equal(Interval[-1,1], (full - 8 * Interval::PI).cos)
1180
- end
1181
-
1182
- def test_tan
1183
- assert_equal(Interval[0], Interval[0].tan)
1184
- assert_equal(Interval[], Interval[].tan)
1185
- assert_equal(Interval[-Infinity, Infinity], Interval[0,6].tan)
1186
- assert_equal(Interval[-Infinity, Infinity], (-Interval::PI/2 | Interval::PI/2).hull.tan)
1187
- assert_equal(Interval[-Infinity, Infinity], (- Interval::PI/4 | Interval::PI * 1.25).hull.tan)
1188
- assert_equal(Interval[-Infinity, Infinity], (4.75 *Interval::PI | Interval::PI * 6.25).hull.tan)
1189
-
1190
- assert_equal(2 ** -51, Interval::PI.tan.width)
1191
- assert_include(Interval::PI.tan, 0)
1192
- assert_equal(3 * 2 ** -53, (Interval::PI/4).tan.width)
1193
- assert_include((Interval::PI/4).tan, 1)
1194
-
1195
- x = (Interval::PI/4 | Interval::PI * 0.75).hull
1196
- assert_equal((Interval[x.sup].tan | -Infinity).hull | (Interval[x.inf].tan | Infinity).hull, x.tan)
1197
-
1198
- x = (Interval::PI | -Interval::PI).hull/4
1199
- assert_equal((Interval[x.inf].tan | Interval[x.sup].tan).hull, x.tan)
1200
- end
1201
-
1202
- end end
1203
-
1204
- Test::Unit.run = (__FILE__ != $0)
754
+ require File.dirname(__FILE__) + '/../test/test_interval.rb' if __FILE__ == $0