intervals 0.3.63 → 0.4.75

Sign up to get free protection for your applications and to get access to all the features.
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