intervals 0.3.56

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/VERSION.txt +1 -0
  2. data/ext/crlibm/AUTHORS +2 -0
  3. data/ext/crlibm/COPYING +504 -0
  4. data/ext/crlibm/ChangeLog +80 -0
  5. data/ext/crlibm/INSTALL +182 -0
  6. data/ext/crlibm/Makefile.am +84 -0
  7. data/ext/crlibm/Makefile.in +530 -0
  8. data/ext/crlibm/NEWS +0 -0
  9. data/ext/crlibm/README +31 -0
  10. data/ext/crlibm/TODO +47 -0
  11. data/ext/crlibm/VERSION +1 -0
  12. data/ext/crlibm/aclocal.m4 +989 -0
  13. data/ext/crlibm/atan-itanium.c +846 -0
  14. data/ext/crlibm/atan-pentium.c +261 -0
  15. data/ext/crlibm/atan_accurate.c +244 -0
  16. data/ext/crlibm/atan_accurate.h +191 -0
  17. data/ext/crlibm/atan_fast.c +324 -0
  18. data/ext/crlibm/atan_fast.h +678 -0
  19. data/ext/crlibm/config.guess +1461 -0
  20. data/ext/crlibm/config.sub +1566 -0
  21. data/ext/crlibm/configure +7517 -0
  22. data/ext/crlibm/configure.ac +364 -0
  23. data/ext/crlibm/crlibm.h +125 -0
  24. data/ext/crlibm/crlibm_config.h +149 -0
  25. data/ext/crlibm/crlibm_config.h.in +148 -0
  26. data/ext/crlibm/crlibm_private.c +293 -0
  27. data/ext/crlibm/crlibm_private.h +658 -0
  28. data/ext/crlibm/csh_fast.c +631 -0
  29. data/ext/crlibm/csh_fast.h +771 -0
  30. data/ext/crlibm/double-extended.h +496 -0
  31. data/ext/crlibm/exp-td.c +962 -0
  32. data/ext/crlibm/exp-td.h +685 -0
  33. data/ext/crlibm/exp_accurate.c +197 -0
  34. data/ext/crlibm/exp_accurate.h +85 -0
  35. data/ext/crlibm/gappa/log-de-E0-logir0.gappa +106 -0
  36. data/ext/crlibm/gappa/log-de-E0.gappa +79 -0
  37. data/ext/crlibm/gappa/log-de.gappa +81 -0
  38. data/ext/crlibm/gappa/log-td-E0-logir0.gappa +126 -0
  39. data/ext/crlibm/gappa/log-td-E0.gappa +143 -0
  40. data/ext/crlibm/gappa/log-td-accurate-E0-logir0.gappa +230 -0
  41. data/ext/crlibm/gappa/log-td-accurate-E0.gappa +213 -0
  42. data/ext/crlibm/gappa/log-td-accurate.gappa +217 -0
  43. data/ext/crlibm/gappa/log-td.gappa +156 -0
  44. data/ext/crlibm/gappa/trigoSinCosCase3.gappa +204 -0
  45. data/ext/crlibm/gappa/trigoTanCase2.gappa +73 -0
  46. data/ext/crlibm/install-sh +269 -0
  47. data/ext/crlibm/log-de.c +431 -0
  48. data/ext/crlibm/log-de.h +732 -0
  49. data/ext/crlibm/log-td.c +852 -0
  50. data/ext/crlibm/log-td.h +819 -0
  51. data/ext/crlibm/log10-td.c +906 -0
  52. data/ext/crlibm/log10-td.h +823 -0
  53. data/ext/crlibm/log2-td.c +935 -0
  54. data/ext/crlibm/log2-td.h +821 -0
  55. data/ext/crlibm/maple/atan.mpl +359 -0
  56. data/ext/crlibm/maple/common-procedures.mpl +997 -0
  57. data/ext/crlibm/maple/csh.mpl +446 -0
  58. data/ext/crlibm/maple/double-extended.mpl +151 -0
  59. data/ext/crlibm/maple/exp-td.mpl +195 -0
  60. data/ext/crlibm/maple/log-de.mpl +243 -0
  61. data/ext/crlibm/maple/log-td.mpl +316 -0
  62. data/ext/crlibm/maple/log10-td.mpl +345 -0
  63. data/ext/crlibm/maple/log2-td.mpl +334 -0
  64. data/ext/crlibm/maple/trigo.mpl +728 -0
  65. data/ext/crlibm/maple/triple-double.mpl +58 -0
  66. data/ext/crlibm/missing +198 -0
  67. data/ext/crlibm/mkinstalldirs +40 -0
  68. data/ext/crlibm/rem_pio2_accurate.c +219 -0
  69. data/ext/crlibm/rem_pio2_accurate.h +53 -0
  70. data/ext/crlibm/scs_lib/AUTHORS +3 -0
  71. data/ext/crlibm/scs_lib/COPYING +504 -0
  72. data/ext/crlibm/scs_lib/ChangeLog +16 -0
  73. data/ext/crlibm/scs_lib/INSTALL +215 -0
  74. data/ext/crlibm/scs_lib/Makefile.am +18 -0
  75. data/ext/crlibm/scs_lib/Makefile.in +328 -0
  76. data/ext/crlibm/scs_lib/NEWS +0 -0
  77. data/ext/crlibm/scs_lib/README +9 -0
  78. data/ext/crlibm/scs_lib/TODO +4 -0
  79. data/ext/crlibm/scs_lib/addition_scs.c +623 -0
  80. data/ext/crlibm/scs_lib/config.guess +1461 -0
  81. data/ext/crlibm/scs_lib/config.sub +1566 -0
  82. data/ext/crlibm/scs_lib/configure +6226 -0
  83. data/ext/crlibm/scs_lib/division_scs.c +110 -0
  84. data/ext/crlibm/scs_lib/double2scs.c +174 -0
  85. data/ext/crlibm/scs_lib/install-sh +269 -0
  86. data/ext/crlibm/scs_lib/missing +198 -0
  87. data/ext/crlibm/scs_lib/mkinstalldirs +40 -0
  88. data/ext/crlibm/scs_lib/multiplication_scs.c +456 -0
  89. data/ext/crlibm/scs_lib/poly_fct.c +112 -0
  90. data/ext/crlibm/scs_lib/print_scs.c +73 -0
  91. data/ext/crlibm/scs_lib/rand_scs.c +63 -0
  92. data/ext/crlibm/scs_lib/scs.h +353 -0
  93. data/ext/crlibm/scs_lib/scs2double.c +391 -0
  94. data/ext/crlibm/scs_lib/scs2mpf.c +58 -0
  95. data/ext/crlibm/scs_lib/scs2mpfr.c +61 -0
  96. data/ext/crlibm/scs_lib/scs_private.c +23 -0
  97. data/ext/crlibm/scs_lib/scs_private.h +133 -0
  98. data/ext/crlibm/scs_lib/tests/tbx_timing.h +102 -0
  99. data/ext/crlibm/scs_lib/wrapper_scs.h +486 -0
  100. data/ext/crlibm/scs_lib/zero_scs.c +52 -0
  101. data/ext/crlibm/stamp-h.in +1 -0
  102. data/ext/crlibm/tests/Makefile.am +43 -0
  103. data/ext/crlibm/tests/Makefile.in +396 -0
  104. data/ext/crlibm/tests/blind_test.c +148 -0
  105. data/ext/crlibm/tests/generate_test_vectors.c +258 -0
  106. data/ext/crlibm/tests/soak_test.c +334 -0
  107. data/ext/crlibm/tests/test_common.c +627 -0
  108. data/ext/crlibm/tests/test_common.h +28 -0
  109. data/ext/crlibm/tests/test_perf.c +570 -0
  110. data/ext/crlibm/tests/test_val.c +249 -0
  111. data/ext/crlibm/trigo_accurate.c +500 -0
  112. data/ext/crlibm/trigo_accurate.h +331 -0
  113. data/ext/crlibm/trigo_fast.c +1219 -0
  114. data/ext/crlibm/trigo_fast.h +639 -0
  115. data/ext/crlibm/triple-double.h +878 -0
  116. data/ext/extconf.rb +31 -0
  117. data/ext/fpu.c +107 -0
  118. data/ext/jamis-mod.rb +591 -0
  119. data/lib/fpu.rb +287 -0
  120. data/lib/interval.rb +1170 -0
  121. data/lib/intervals.rb +212 -0
  122. data/lib/struct_float.rb +133 -0
  123. data/test/data_atan.txt +360 -0
  124. data/test/data_cos.txt +346 -0
  125. data/test/data_cosh.txt +3322 -0
  126. data/test/data_exp.txt +3322 -0
  127. data/test/data_log.txt +141 -0
  128. data/test/data_sin.txt +140 -0
  129. data/test/data_sinh.txt +3322 -0
  130. data/test/data_tan.txt +342 -0
  131. metadata +186 -0
data/lib/interval.rb ADDED
@@ -0,0 +1,1170 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # Definitions for the class Interval.
4
+ #
5
+ # Copyright (c) 2006 Stefano Taschini <taschini@ieee.org>.
6
+ # Licensed under the terms of LGPL: http://www.gnu.org/copyleft/lesser.html
7
+
8
+ # To control the FPU's rounding mode
9
+ require "fpu"
10
+
11
+ class Numeric
12
+ #
13
+ # Define a degenerate interval from a single value.
14
+ #
15
+ # 3.to_interval # => Interval[3]
16
+ #
17
+ def to_interval
18
+ Interval[self]
19
+ end
20
+ end
21
+
22
+ # A class representing the finite union of closed mathematical intervals
23
+ # in the extended real set.
24
+ #
25
+ # The real set is extended with +Infinity and -Infinity, and the intervals
26
+ # are closed, i.e. they include their extrema.
27
+ class Interval
28
+ include Enumerable
29
+
30
+ # Create a closed (multi-)interval with the given numerical extrema.
31
+ #
32
+ # Interval[3] # In mathematical notation: [3,3]
33
+ # Interval[1,2] # In mathematical notation: [1,2]
34
+ # Interval[[1,2],[3,4]] # Union of [1,2] and [3,4]
35
+ #
36
+ # Note that the created interval is always in canonical form:
37
+ #
38
+ # Interval[[1,3],[2,4]] # => Interval[1, 4]
39
+ #
40
+ def Interval.[](*array)
41
+ make(
42
+ if array.empty?
43
+ []
44
+ elsif array.first.kind_of?(Numeric)
45
+ [Simple[*array]]
46
+ else
47
+ array.select{|x| !x.empty?}.map { |x| Simple[*x] }
48
+ end
49
+ )
50
+ end
51
+
52
+ # Create a closed (multi-)interval from a set of simple intervals.
53
+ #
54
+ # Interval.make(Interval[1,2], Interval[3,4])
55
+ # # => Interval[[1, 2], [3, 4]]
56
+ #
57
+ def Interval.make(comps)
58
+ l = []
59
+ comps.sort_by{|x| x.inf}.each{|x|
60
+ if x.sup < x.inf
61
+ # skip it
62
+ elsif l.empty? || x.inf > l.last.sup
63
+ l <<= x
64
+ elsif x.sup > l.last.sup
65
+ l[-1] = Simple.new(l.last.inf, x.sup)
66
+ end
67
+ }
68
+ if l.size == 1
69
+ l.first
70
+ else
71
+ Interval::Complex.new(l)
72
+ end
73
+ end
74
+
75
+ # Returns a list of the parameters that can be used to reconstruct the
76
+ # interval.
77
+ #
78
+ # a = Interval[1,2] # => Interval[1, 2]
79
+ # b = a.construction # => [1, 2]
80
+ # Interval[*b] == a # => true
81
+ #
82
+ def construction
83
+ map{|x| x.extrema.uniq}
84
+ end
85
+
86
+ # True if the interval is _simple_, i.e., if it has only one
87
+ # connected component.
88
+ #
89
+ # Interval[1,2].simple? # => true
90
+ # Interval[[1,2],[3,4]].simple?
91
+ # # => false
92
+ # If simple? is true, then the object is in fact of class
93
+ # Interval::Simple.
94
+ #
95
+ # Interval[1,2].class # => Interval::Simple
96
+ # Interval[1,2].midpoint # => 1.5
97
+ # Interval[[1,2],[3,4]].midpoint
98
+ # # raises a NoMethodError exception
99
+ #
100
+ def simple?
101
+ false
102
+ end
103
+
104
+ # Overrides Object#inspect, returning a string representation of the interval.
105
+ #
106
+ # Interval[1,2].inspect #= > "Interval[1, 2]"
107
+
108
+ def inspect
109
+ "Interval" + construction.inspect
110
+ end
111
+
112
+ # Overrides Object#to_s and uses #inspect to create a string representation of the interval.
113
+ def to_s
114
+ inspect
115
+ end
116
+
117
+ # Two intervals are equal if and only if they have equal components.
118
+ #
119
+ # Interval[[1,3],[2,4]] == Interval[1,4]
120
+ # # => true
121
+ def == (other)
122
+ self.class === other && self.components == other.components
123
+ end
124
+
125
+ # True if a point _x_ belongs to the interval.
126
+ #
127
+ # Interval[[1,2],[3,4]].include?(1.5)
128
+ # # => true
129
+ # Interval[[1,2],[3,4]].include?(2.5)
130
+ # # => false
131
+ def include?(x)
132
+ any?{|i| i.include?(x)}
133
+ end
134
+
135
+ # Return itself.
136
+ def to_interval
137
+ self
138
+ end
139
+
140
+ # Make _other_ into an interval.
141
+ def coerce (other)
142
+ [other.to_interval, self]
143
+ end
144
+
145
+ # Unitary minus: applied to _I_ returns -_I_.
146
+ #
147
+ # -Interval[1,2] # => Interval[-2, -1]
148
+ #
149
+ def -@
150
+ self.class.new map{|x| -x}.reverse
151
+ end
152
+
153
+ # The inverse of the interval, _I_.+inverse+ is the same as 1/_I_.
154
+ #
155
+ # Interval[1,2].inverse # => Interval[0.5, 1.0]
156
+ # Interval[-2,4].inverse # => Interval[[-Infinity, -0.5], [0.25, Infinity]]
157
+ #
158
+ def inverse
159
+ # implemented below
160
+ end
161
+
162
+ # The exponential function.
163
+ #
164
+ # Interval[[-Infinity,0],[1,Infinity]].exp
165
+ # # => Interval[[0,1],[Math::E,Infinity]]
166
+ #
167
+ def exp
168
+ # implemented below
169
+ end
170
+
171
+ # The logarithm function.
172
+ #
173
+ # Interval[1,Math::E].log # Interval[0,1]
174
+ # Interval[-1,+1].log # Interval[-Infinity,0]
175
+ #
176
+ def log
177
+ # implemented below
178
+ end
179
+
180
+ # The arc tangent function.
181
+ #
182
+ # 4 * Interval[1].atan # => Interval::PI
183
+ #
184
+ def atan
185
+ # implemented below
186
+ end
187
+
188
+ # The cosine function.
189
+ #
190
+ # (Interval::PI/3).cos # => Interval[0.5, 0.5]
191
+ #
192
+ def cos
193
+ # implemented below
194
+ end
195
+
196
+ # The sine function.
197
+ #
198
+ # (Interval::PI/6).sin # => Interval[0.5, 0.5]
199
+ #
200
+ def sin
201
+ # implemented below
202
+ end
203
+
204
+ # The tangent function.
205
+ #
206
+ # The cosine function. # => Interval[1.0, 1.0]
207
+ #
208
+ def tan
209
+ # implemented below
210
+ end
211
+
212
+ # Hyperbolic cosine.
213
+ def cosh
214
+ # implemented below
215
+ end
216
+
217
+ # Hyperbolic sine.
218
+ def sinh
219
+ # implemented below
220
+ end
221
+
222
+ ## Implement unary operations
223
+ [:inverse, :exp, :log, :atan, :cos, :sin, :tan, :cosh, :sinh].each {|op|
224
+ define_method(op) {
225
+ Interval.make(map{|x| x.send(op).components}.flatten)
226
+ }
227
+ }
228
+
229
+ # Integer power.
230
+ #
231
+ # Interval[-2,2]**2 # => Interval[0, 4]
232
+ #
233
+ def ** (n)
234
+ Interval.make(map{|x| (x**n).components}.flatten)
235
+ end
236
+
237
+ # Sum of intervals.
238
+ #
239
+ # Interval[1,2] + Interval[3,4]
240
+ # # => Interval[4, 6]
241
+ # Interval[2] + Interval[2]
242
+ # # => Interval[4]
243
+ #
244
+ # Note that
245
+ #
246
+ # Interval[-Infinity] + Interval[Infinity]
247
+ # # => Interval[-Infinity, Infinity]
248
+ #
249
+ def + (other)
250
+ # implemented below
251
+ end
252
+
253
+ # Multiplication of intervals.
254
+ #
255
+ # Interval[1,2] * Intervals[3,4]
256
+ # # => Interval[3, 8]
257
+ # Interval[2] * Interval[2]
258
+ # # => Interval[4]
259
+ #
260
+ # Note that
261
+ #
262
+ # Interval[0,1] * Interval[2,Infinity]
263
+ # # => Interval[-Infinity, Infinity]
264
+ #
265
+ def * (other)
266
+ # implemented below
267
+ end
268
+
269
+ # Set intersection.
270
+ #
271
+ # Interval[1,3] & Interval[2,4]
272
+ # # => Interval[2,3]
273
+ # Interval[1,2] & Interval[3,4]
274
+ # # => Interval[]
275
+ # (Interval[1,2] & Interval[3,4]).empty?
276
+ # # => true
277
+ #
278
+ def & (other)
279
+ # implemented below
280
+ end
281
+
282
+ ## Implement binary operations: Sum (+), Multiplication (*) and Intersection (&)
283
+ [[:+, :add], [:*, :multiply], [:&, :intersect]].each {|op, meth|
284
+ define_method(op) {|other|
285
+ Interval.make(other.to_interval.map {|y| self.map {|x| x.send(meth,y) } }.flatten)
286
+ }
287
+ }
288
+
289
+ # Subtraction: _A_ - _B_ is equivalent to _A_ + (-_B_).
290
+ def - (other)
291
+ self + (-other)
292
+ end
293
+
294
+ # Division: _A_ / _B_ is equivalent to _A_ * (_B_ ** -1).
295
+ def / (other)
296
+ self * other.to_interval.inverse
297
+ end
298
+
299
+ # Set union.
300
+ #
301
+ # Interval[1,3] | Interval[2,4]
302
+ # # => Interval[1, 4]
303
+ #
304
+ def | (other)
305
+ Interval.make(other.to_interval.components + self.components)
306
+ end
307
+
308
+ # True if the interval has no elements.
309
+ def empty?
310
+ components.empty?
311
+ end
312
+
313
+ # An interval is sharp if each pair of extrema differ by at most a bit in the
314
+ # least significant position.
315
+ #
316
+ # Interval[3].sharp? # => true
317
+ # Interval[1,2].sharp? # => false
318
+ # (1/Interval[3.0]).sharp? # => true
319
+ # Interval[[1],[2]].sharp? # => true
320
+ #
321
+ def sharp?
322
+ all? {|x| x.sharp?}
323
+ end
324
+
325
+ # The hull is the smallest simple interval containing the interval itself.
326
+ #
327
+ # Interval[[1,2],[3,4]] # => Interval[1, 4]
328
+ #
329
+ def hull
330
+ if empty?
331
+ Interval[]
332
+ else
333
+ Interval[components.first.inf, components.last.sup]
334
+ end
335
+ end
336
+
337
+ @@newtonOpts = {
338
+ :maxIterations => 100,
339
+ :verbose => false
340
+ }
341
+
342
+ # Solve a non-linear equation using the Newton-Raphson method,
343
+ # finding all solutions in a in interval.
344
+ #
345
+ # For instance, to solve
346
+ # x**3 == x
347
+ # we rewrite it first in the form
348
+ # x**3 - x == 0
349
+ # The left-hand side of this equation has derivative
350
+ # 3* x**2 - 1
351
+ # To find all solutions in [-100,100] we call
352
+ # Interval[-100,100].newton(proc {|x| x**3 - x}, proc {|x| 3* x**2 - 1})
353
+ # # => Interval[[-1.0], [-0.0], [1.0]]
354
+ # a sharp result showing the three roots -1, 0 and +1.
355
+ #
356
+ def newton(f, fp, opts = {})
357
+ effectiveOpts = @@newtonOpts.dup.update(opts)
358
+ verbose = effectiveOpts[:verbose]
359
+ puts "Starting on #{self}" if verbose
360
+ step = proc {|w,ww| (w - f.call(Interval[w]) / fp.call(ww) ) & ww}
361
+ self.map{|xx|
362
+ effectiveOpts[:maxIterations].times{
363
+ previous = xx;
364
+ xx = step.call(xx.midpoint,xx)
365
+ if previous == xx
366
+ if xx.sharp?
367
+ puts "Sharp fixed point #{xx}" if verbose
368
+ xx = Interval[xx.extrema.select {|x| f.call(Interval[x]).include?(0)}]
369
+ break
370
+ end
371
+ nonminimal_extrema = xx.extrema.reject {|x| f.call(Interval[x]).include?(0)}
372
+ if nonminimal_extrema == [] then
373
+ puts "Unsharp fixed point #{xx}" if verbose
374
+ break
375
+ end
376
+ if nonminimal_extrema.each {|x|
377
+ yy = step.call(x,xx)
378
+ if yy != xx
379
+ xx = yy;
380
+ break
381
+ end
382
+ }
383
+ xx = Interval[
384
+ if nonminimal_extrema.include?(xx.inf)
385
+ xx.inf + xx.inf.ulp
386
+ else
387
+ xx.inf
388
+ end,
389
+ if nonminimal_extrema.include?(xx.sup)
390
+ xx.sup - xx.sup.ulp
391
+ else
392
+ xx.sup
393
+ end]
394
+ end
395
+ end
396
+ if xx.empty?
397
+ puts "No solution" if verbose
398
+ break
399
+ elsif ! xx.simple?
400
+ puts "Branch splitting" if verbose
401
+ xx = xx.newton(f,fp,opts)
402
+ break
403
+ end
404
+ } && verbose && puts("Failed convergence #{effectiveOpts[:maxIterations]}")
405
+ xx
406
+ }. inject{|a,x| a |=x}
407
+ end
408
+
409
+ end
410
+
411
+ # Implements simple intervals. A simple interval is an interval with a single
412
+ # component, i.e., a connected set of real numbers (extended with plus and minus
413
+ # infinity.)
414
+ class Interval::Simple < Interval
415
+ attr :inf
416
+ attr :sup
417
+
418
+ include Enumerable
419
+
420
+ # Implements Enumerable#each
421
+ def each
422
+ yield(self)
423
+ self
424
+ end
425
+
426
+ # Return an array with one element, itself.
427
+ def components
428
+ [self]
429
+ end
430
+
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
+ # Constructs a simple interval, with given lower and upper bounds.
441
+ #
442
+ # Interval::Simple.new(1,1) # => Interval[1]
443
+ # Interval::Simple.new(1,2) # => Interval[1,2]
444
+ #
445
+ def initialize (a, b)
446
+ if (a.respond_to?(:nan?) && a.nan? ) || (b.respond_to?(:nan?) && b.nan?)
447
+ @inf, @sup = -Infinity, Infinity
448
+ else
449
+ @inf, @sup = a, b
450
+ end
451
+ freeze
452
+ end
453
+
454
+ # Overrides Interval#construction
455
+ def construction # :nodoc:
456
+ extrema.uniq
457
+ end
458
+
459
+ # Implements Interval#simple?, returning true.
460
+ def simple? # :nodoc:
461
+ true
462
+ end
463
+
464
+ # Two simple intervals are equal if they have same inf and sup.
465
+ def == (other)
466
+ self.class == other.class && inf == other.inf && sup == other.sup
467
+ end
468
+
469
+ # Implements Interval#include?.
470
+ def include?(x) # :nodoc:
471
+ inf <= x && x <= sup
472
+ end
473
+
474
+ # Returns the array with inf and sup.
475
+ #
476
+ # Interval[1,2].extrema # => [1, 2]
477
+ #
478
+ def extrema
479
+ [inf,sup]
480
+ end
481
+
482
+ # The interval's width is sup - inf.
483
+ #
484
+ # Interval[2].width # => 0
485
+ # Interval[2,3].width # => 1
486
+ #
487
+ def width
488
+ sup - inf
489
+ end
490
+
491
+ # The point in the middle of the interval.
492
+ #
493
+ # Interval[1,3].midpoint # => 2.0
494
+ #
495
+ def midpoint
496
+ (inf + sup) * 2 **-1
497
+ end
498
+
499
+ # Used to implement Interval's plus operator (\+).
500
+ def add (other)
501
+ self.class.new(
502
+ FPU.down {inf + other.inf},
503
+ FPU.up {sup + other.sup})
504
+ end
505
+
506
+ # Unitary minus.
507
+ def -@ # :nodoc:
508
+ self.class.new(-sup,-inf)
509
+ end
510
+
511
+ # Used to implement Interval's multiplicative operator (\*).
512
+ def multiply (other)
513
+ self.class.new(
514
+ FPU.down {
515
+ [inf * other.inf, inf * other.sup,
516
+ sup * other.inf, sup * other.sup]}.min,
517
+ FPU.up {
518
+ [inf * other.inf, inf * other.sup,
519
+ sup * other.inf, sup * other.sup]}.max)
520
+ rescue ArgumentError
521
+ self.class.new(-Infinity, Infinity)
522
+ end
523
+
524
+ # Implements Interval#inverse.
525
+ def inverse # :nodoc:
526
+ if include?(0) then
527
+ Interval[
528
+ [-Infinity, FPU::up { inf == 0 ? -Infinity : inf**-1 }],
529
+ [FPU::down { sup == 0 ? Infinity : sup**-1 }, Infinity]]
530
+ else
531
+ self.class.new(
532
+ FPU::down { sup ** -1 },
533
+ FPU::up { inf ** -1 })
534
+ end
535
+ end
536
+
537
+ # Implements Interval's power operator.
538
+ def ** (n) # :nodoc:
539
+ if n < 0
540
+ (self ** -n).inverse
541
+ elsif inf > 0
542
+ self.class.new(
543
+ FPU::down { FPU.power(inf, n) },
544
+ FPU::up { FPU.power(sup, n) })
545
+ elsif sup < 0
546
+ if (-1) ** n > 0
547
+ (-self)**n
548
+ else
549
+ - (-self)**n
550
+ end
551
+ elsif (-1) ** n > 0
552
+ self.class.new(0, FPU::up {[FPU.power(inf, n), FPU.power(sup, n)]}.max )
553
+ else
554
+ self.class.new(
555
+ FPU::down { FPU.power(inf, n) },
556
+ FPU::up { FPU.power(sup, n) })
557
+ end
558
+ end
559
+
560
+ # Implements Interval's & operator.
561
+ def intersect (other)
562
+ self.class.new([inf,other.inf].max, [sup,other.sup].min)
563
+ end
564
+
565
+ # Implements Interval#sharp?
566
+ def sharp? # :nodoc:
567
+ w = width
568
+ if w == 0
569
+ true
570
+ elsif w.kind_of?(Float) && (inf >= 0 || sup <= 0)
571
+ s1, s2 = extrema.map{|x| x.abs}.sort
572
+ s1 + s1.ulp == s2
573
+ else
574
+ false
575
+ end
576
+ end
577
+
578
+ # Implements Interval#exp
579
+ def exp #:nodoc:
580
+ self.class.new(FPU.exp_down(inf), FPU.exp_up(sup))
581
+ end
582
+
583
+ # Implements Interval#atan
584
+ def atan #:nodoc:
585
+ self.class.new(FPU.atan_down(inf), FPU.atan_up(sup))
586
+ end
587
+
588
+ # Implements Interval#sinh
589
+ def sinh #:nodoc:
590
+ self.class.new(FPU.sinh_down(inf), FPU.sinh_up(sup))
591
+ end
592
+
593
+ # Implements Interval#log
594
+ def log #:nodoc:
595
+ if inf >= 0
596
+ self.class.new(FPU.log_down(inf), FPU.log_up(sup))
597
+ elsif sup >= 0
598
+ self.class.new(-Infinity, FPU.log_up(sup))
599
+ else
600
+ Interval[]
601
+ end
602
+ end
603
+
604
+ # Implements Interval#cosh
605
+ def cosh #:nodoc:
606
+ if inf >=0
607
+ self.class.new(FPU.cosh_down(inf), FPU.cosh_up(sup))
608
+ elsif sup <= 0
609
+ self.class.new(FPU.cosh_down(sup), FPU.cosh_up(inf))
610
+ else
611
+ self.class.new(0,FPU.cosh_up([-inf,sup].max))
612
+ end
613
+ end
614
+
615
+ # Implements Interval#cos
616
+ def cos #:nodoc:
617
+ return Interval[-1,1] if inf.abs == Infinity || sup.abs == Infinity
618
+ p = inf.divmod(Math::PI).first.to_i
619
+ self.class.new(
620
+ if include?((2*((p-1).div(2))+3) * Math::PI)
621
+ -1
622
+ else
623
+ [FPU.cos_down(inf), FPU.cos_down(sup)].min
624
+ end,
625
+ if include?((2*(p.div(2))+2) * Math::PI)
626
+ +1
627
+ else
628
+ [FPU.cos_up(inf), FPU.cos_up(sup)].max
629
+ end)
630
+ end
631
+
632
+ # Implements Interval#sin
633
+ def sin #:nodoc:
634
+ return Interval[-1,1] if inf.abs == Infinity || sup.abs == Infinity
635
+ q = inf.divmod(Math::PI/2).first.to_i
636
+ p = (q-1).div(2)
637
+ self.class.new(
638
+ if include?((2*((p-1).div(2))+3.5) * Math::PI)
639
+ -1
640
+ else
641
+ [FPU.sin_down(inf), FPU.sin_down(sup)].min
642
+ end,
643
+ if include?((2*(p.div(2))+2.5) * Math::PI)
644
+ +1
645
+ else
646
+ [FPU.sin_up(inf), FPU.sin_up(sup)].max
647
+ end)
648
+ end
649
+
650
+ # Implement Interval#tan
651
+ def tan #:nodoc:
652
+ q = inf.divmod(Math::PI/2).first.to_i
653
+ p = (q-1).div(2)
654
+ if include?(Math::PI * (p+2.5))
655
+ self.class.new(-Infinity,Infinity)
656
+ elsif include?(Math::PI * (p+1.5))
657
+ Interval[[-Infinity,FPU.tan_up(sup)],[FPU.tan_down(inf),Infinity]]
658
+ else
659
+ self.class.new(FPU.tan_down(inf),FPU.tan_up(sup))
660
+ end
661
+ end
662
+
663
+ end
664
+
665
+ # Implements an interval with multiple components.
666
+ class Interval::Complex < Interval
667
+
668
+ # The array with the interval's components.
669
+ attr :components
670
+
671
+ def initialize (array) # :nodoc:
672
+ @components = array
673
+ freeze
674
+ end
675
+
676
+ # Implements Enumerable#each.
677
+ def each
678
+ components.each { |o| yield(o) }
679
+ self
680
+ end
681
+
682
+ end
683
+
684
+ class Range
685
+
686
+ # Convert to Interval.
687
+ #
688
+ # (1.2 .. 5.3).to_interval # => Interval[1.2, 5.3]
689
+ # (1 ... 4).to_interval # => Interval[1, 3]
690
+ # (1 ... 3.1).to_interval # Fails
691
+ #
692
+ def to_interval
693
+ Interval[first,
694
+ if exclude_end?
695
+ (last - 1).succ - 1
696
+ else
697
+ last
698
+ end]
699
+ end
700
+
701
+ end
702
+
703
+ class Interval
704
+
705
+ # The sharp interval that includes which Euler's constant.
706
+ E = Math::E + Interval[0, 2 ** -51]
707
+
708
+ # The sharp interval that includes Pi.
709
+ PI = Math::PI + Interval[0, 2 ** -51]
710
+
711
+ end
712
+
713
+ require 'test/unit'
714
+
715
+ # Assertions to be used when testing intervals.
716
+ module Interval::Assertions
717
+
718
+ def assert_sharp(x)
719
+ assert(x.sharp?, x.inspect + " should be sharp.")
720
+ assert((-x).sharp?, (-x).inspect + " should be sharp.")
721
+ end
722
+
723
+ # Assert that an interval is not sharp.
724
+ def assert_fuzzy(x)
725
+ assert(!x.sharp?, x.inspect + " should not be sharp.")
726
+ assert(!(-x).sharp?, (-x).inspect + " should not be sharp.")
727
+ end
728
+
729
+ # Assert that +s+ is a solution to +f+ == 0. Unless the +weak+ flag is set,
730
+ # assert also that +s+ == +expected+.
731
+ # If the +weak+ flag is set, assert that +s+ includes +expected+.
732
+ def assert_solution(s,f,expected, weak = nil)
733
+ res = s.map{|c| f.call(c)}.inject{|a,c| a|c}
734
+ # Did something spectacarly unexpected happen?
735
+ assert(res.simple?, res)
736
+ # Is it a solution?
737
+ assert(res.include?(0), res)
738
+ # Is it minimal?
739
+ assert(s.all? {|x| x.extrema.all? {|y| f.call(Interval[y]).include?(0)}}, s.inspect +
740
+ " is non minmal")
741
+ # Is it the expected solution?
742
+ if weak
743
+ # check the granularity
744
+ assert_equal(expected.components.size, s.components.size, [expected,s].inspect)
745
+ # check for inclusion
746
+ assert_equal(expected, s & expected, s)
747
+ else
748
+ # check for equality
749
+ assert_equal(expected,s)
750
+ end
751
+ end
752
+
753
+ end
754
+
755
+ # Tests Interval fundamentals: construction, equality and inspection.
756
+ class Interval::TestFundamentals < Test::Unit::TestCase
757
+
758
+ def test_constructor_and_equality
759
+ tester = proc {|i,ex,klass|
760
+ assert_equal(klass, i.class)
761
+ assert_equal(ex, i.construction)
762
+ assert_equal(i, Interval[*i.construction])
763
+ }
764
+
765
+ tester.call Interval[1], [1], Interval::Simple
766
+ tester.call Interval[1,2], [1,2], Interval::Simple
767
+ tester.call Interval[[1,2],[3,4]], [[1,2],[3,4]], Interval::Complex
768
+ tester.call Interval[[1],[2]], [[1],[2]], Interval::Complex
769
+ tester.call Interval[[1]], [1], Interval::Simple
770
+ tester.call Interval[2,0/0.0], [-Infinity,+Infinity], Interval::Simple
771
+ tester.call Interval[0/0.0,9], [-Infinity,+Infinity], Interval::Simple
772
+ tester.call Interval[[1,3],[4,6],[2,5],[9,9]], [[1,6],[9]], Interval::Complex
773
+ end
774
+
775
+ def test_construction_failure
776
+ assert_raise(NoMethodError) { Interval[1,[2,3]] }
777
+ assert_raise(ArgumentError) { Interval[1,2,3] }
778
+ assert_raise(NoMethodError) { Interval[1,[2,3]] }
779
+ assert_raise(NoMethodError) { Interval[[1],2] }
780
+ end
781
+
782
+ def test_inequality
783
+ assert(Interval[1,2] != Interval[1,3])
784
+ assert(Interval[1,2] != Interval[0,2])
785
+ assert(Interval[1,2] != Interval[0,3])
786
+ assert(Interval[1,2] != 3)
787
+ assert(Interval[[1,2],[3,4]] != Interval[[1,0],[3,4]])
788
+ end
789
+
790
+ def test_inspect_and_to_s
791
+ tester = proc {|s|
792
+ i = eval(s)
793
+ assert_equal(s,i.inspect)
794
+ assert_equal(s,i.to_s)
795
+ }
796
+ tester.call "Interval[1]"
797
+ tester.call "Interval[1, 2]"
798
+ tester.call "Interval[[1, 2], [3, 4]]"
799
+ tester.call "Interval[[1, 2], [4], [5, 6], [Infinity]]"
800
+ tester.call "Interval[1, 2]"
801
+ end
802
+
803
+ end
804
+
805
+ # Tests the arithmetic of Interval::Simple.
806
+ class Interval::TestSimpleArithmetic < Test::Unit::TestCase
807
+
808
+ def test_plus
809
+ assert_equal(Interval[-Infinity,+Infinity], Interval[-Infinity] + Interval[Infinity])
810
+ assert_equal(Interval[4,6], Interval[1,2] + Interval[3,4])
811
+ assert_equal(Interval[3,Infinity], Interval[1,Infinity]+Interval[2])
812
+ assert_equal(Interval[-Infinity,+Infinity],Interval[-Infinity,-1] + Interval[2,+Infinity])
813
+ assert_equal(Interval[-Infinity,+Infinity],Interval[-Infinity] + Interval[8,+Infinity])
814
+ end
815
+
816
+ def test_minus
817
+ assert_equal(Interval[-2,-1], -Interval[1,2])
818
+ end
819
+
820
+ def test_times
821
+ assert_equal(Interval[-Infinity,+Infinity],Interval[Infinity] * Interval[0])
822
+ assert_equal(Interval[+Infinity],Interval[Infinity] * Interval[3])
823
+ assert_equal(Interval[-8,+10], Interval[1,2] * Interval[-4,5])
824
+ assert_equal(Interval[3,8], Interval[1,2] * Interval[3,4])
825
+ assert_equal(Interval[-Infinity,+Infinity],Interval[0,1] * Interval[2,Infinity])
826
+ assert_equal(Interval[2, Infinity], Interval[-Infinity,-2] * Interval[-Infinity,-1])
827
+ end
828
+
829
+ def test_inverse
830
+ assert_equal(Interval[0.5,1],Interval[1,2].inverse)
831
+ assert_equal(Interval[-1,-0.5],(-Interval[1,2]).inverse)
832
+ assert_equal(Interval[[-Infinity,-1],[0.5,+Infinity]],Interval[-1,2].inverse)
833
+ assert_equal(Interval[[-Infinity],[1,+Infinity]],Interval[0,1].inverse)
834
+ end
835
+
836
+ def test_power
837
+ assert_equal((-Interval[1,2]).inverse, (-Interval[1,2]) ** -1)
838
+ assert_equal(Interval[0,4], Interval[-1,2]**2)
839
+ assert_equal(Interval[-27,8], Interval[-3,2]**3)
840
+
841
+ assert_equal(
842
+ Interval[FPU.down{(1/3.0)*(1/3.0)},FPU.up{(1/3.0)*(1/3.0)}],
843
+ (Interval[1]/3.0) ** 2)
844
+
845
+ assert_equal(
846
+ Interval[
847
+ FPU.down{(1/3.0)*(1/3.0)*(1/3.0)},
848
+ FPU.up{(1/3.0)*(1/3.0)*(1/3.0)}],
849
+ (Interval[1]/3.0) ** 3)
850
+ end
851
+
852
+ end
853
+
854
+ # Tests other methods of Interval::Simple.
855
+ class Interval::TestSimpleMethods < Test::Unit::TestCase
856
+
857
+ def test_midpoint
858
+ assert_equal(1.5,Interval[1,2].midpoint)
859
+ assert_raise(NoMethodError){ Interval[[1,2],[3,4]].midpoint }
860
+ end
861
+
862
+ def test_width
863
+ assert_equal(1, Interval[1,2].width)
864
+ assert_equal(1, Interval[1,2].width)
865
+ tester = proc{|x|
866
+ assert_equal(
867
+ 2.0 ** (-(Math.log(x)/Math.log(2)).ceil - 52),
868
+ (1/Interval[x]).width)
869
+ }
870
+ tester.call(3.0)
871
+ tester.call(5.0)
872
+ tester.call(119.0)
873
+ tester.call(34e-4)
874
+ end
875
+
876
+ end
877
+
878
+ # Tests Interval algebra.
879
+ class Interval::TestAlgebra < Test::Unit::TestCase
880
+
881
+ def test_union
882
+ assert_equal(Interval[[1, 6], [9, 9]], Interval[[1, 3],[4, 6]] | Interval[[2, 5], [9,9]])
883
+ end
884
+
885
+ def test_plus
886
+ tester = proc{|x,y,sum|
887
+ assert_equal(sum,x+y)
888
+ assert_equal(sum,y+x)
889
+ }
890
+ tester.call(Interval[[1,2],[10,Infinity]], Interval[[1,9],[-2,-1]], Interval[[-1,1],[2,Infinity]])
891
+ tester.call(Interval[1,9], Interval[[1,2],[10,Infinity]], Interval[2,Infinity])
892
+ tester.call(Interval[1,2], 2, Interval[3,4])
893
+ end
894
+
895
+ def test_intersection
896
+ tester = proc{|x,y,z|
897
+ assert_equal(z, x & y)
898
+ assert_equal(z, y & x)
899
+ }
900
+ tester.call(Interval[1,2], Interval[0,3], Interval[1,2])
901
+ tester.call(Interval[1.1,1.9], Interval[1.3,2.5], Interval[1.3, 1.9])
902
+ tester.call(Interval[1.1,1.9], Interval[0.3,0.7], Interval[])
903
+ end
904
+
905
+ def test_inverse
906
+ assert_equal(Interval[[-Infinity, -2.0],[0.0, Infinity]],Interval[[-0.5,0.5],[0.2,Infinity]].inverse)
907
+ end
908
+
909
+ def test_minus
910
+ assert_equal(Interval[[-4,-3],[-2,-1]], -Interval[[1,2],[3,4]])
911
+ end
912
+
913
+ def test_times
914
+ tester = proc{|x,y,z|
915
+ assert_equal(z,x*y)
916
+ assert_equal(z,y*x)
917
+ }
918
+ tester.call(Interval[[1, 2], [3, 4]], Interval[0.5, 2], Interval[0.5,8])
919
+ tester.call(Interval[1,2], 2, Interval[2,4])
920
+ end
921
+
922
+ def test_division
923
+ assert_equal(Interval[-Infinity, Infinity], Interval[0,1]/Interval[0,1])
924
+ assert_equal(Interval[0.5], Interval[1]/2)
925
+ end
926
+
927
+ def test_power
928
+ assert_equal(Interval[-1,2], (Interval[-1,2]**-1)**-1)
929
+ end
930
+
931
+ end
932
+
933
+ #Tests other Interval methods.
934
+ class Interval::TestMethods < Test::Unit::TestCase
935
+ include Interval::Assertions
936
+
937
+ def test_include?
938
+ assert(Interval[1,2].include?(1.5),"1")
939
+ assert(Interval[1,2].include?(1),"2")
940
+ assert(Interval[1,2].include?(2),"3")
941
+ assert(!Interval[1,2].include?(0),"4")
942
+ assert(!Interval[1,2].include?(4),"5")
943
+ end
944
+
945
+ def test_simple?
946
+ assert(Interval[1,2].simple?)
947
+ assert(!Interval[[1,2],[3,4]].simple?)
948
+ end
949
+
950
+ def test_empty?
951
+ assert(!Interval[1,2].empty?)
952
+ assert(!Interval[[1,2],[4,3]].empty?)
953
+ assert(Interval[].empty?)
954
+ end
955
+
956
+ def test_sharp?
957
+ assert_sharp(Interval[5,5])
958
+ assert_sharp(Interval[[1],[2]])
959
+ assert_fuzzy(Interval[[1],[2,3]])
960
+ assert_fuzzy(Interval[5,6])
961
+ assert_fuzzy(Interval[1.1,1.2])
962
+ assert_fuzzy(Interval[Struct::Float[-1,0,1].to_f,Struct::Float[+1,0,1].to_f])
963
+ assert_sharp(Interval[Struct::Float[1,1022,2**52-1].to_f,1])
964
+ assert_sharp(Interval[Struct::Float[1,1029,2**52-1].to_f,128])
965
+ assert_sharp(Interval[-0.0,0.0])
966
+ assert_sharp(Interval[0.0,Struct::Float[1,0,1].to_f])
967
+ assert_sharp(Interval[6369051672525772, 6369051672525773] * 2.0 ** -52)
968
+ assert_sharp(Interval[6369051672525772, 6369051672525772] * 2.0 ** -52)
969
+ assert_fuzzy(Interval[6369051672525771, 6369051672525773] * 2.0 ** -52)
970
+ assert_fuzzy(Interval[6369051672525771, 6369051672525785] * 2.0 ** -52)
971
+ end
972
+
973
+ def test_hull
974
+ assert_equal(Interval[1,4], Interval[[1,2],[3,4]].hull)
975
+ assert_equal(Interval[1,4], Interval[1,4].hull)
976
+ assert_equal(Interval[], Interval[].hull)
977
+ end
978
+
979
+ def test_conversion_from_range
980
+ assert_equal(Interval[1.2, 5.3], (1.2 .. 5.3).to_interval)
981
+ assert_equal(Interval[1, 4], (1 .. 4).to_interval)
982
+ assert_equal(Interval[1, 3], (1 ... 4).to_interval)
983
+ assert_raise(NoMethodError){ (1 ... 3.1).to_interval }
984
+ end
985
+
986
+ end
987
+
988
+ # Tests the Interval-based non-linear solver.
989
+ class Interval::TestNewton < Test::Unit::TestCase
990
+ include Interval::Assertions
991
+
992
+ def test_sqrt2
993
+ f, fp = proc {|x| x**2 - 2}, proc {|x| 2*x}
994
+ s = Math::sqrt(2)
995
+ assert_equal(6369051672525773 * 2.0 **-52, s)
996
+ assert_equal(Interval[s], Interval[0.1,5.0].newton(f, fp))
997
+ assert_equal(Interval[], Interval[2.0,5.0].newton(f,fp))
998
+ assert_equal(Interval[s], Interval[-1.0,10.0].newton(f,fp))
999
+ assert_equal(Interval[-s], Interval[-5.0,0].newton(f,fp))
1000
+ assert_equal(Interval[[-s],[s]], Interval[-5.0,5.0].newton(f,fp))
1001
+ end
1002
+
1003
+ def test_cubic_1
1004
+ f, fp = proc {|x| x**3 + x - 10}, proc {|x| 3*x**2 + 1}
1005
+ s = Interval[-1,5].newton(f,fp)
1006
+ assert_solution(s, f, Interval[2])
1007
+ end
1008
+
1009
+ def test_cubic_2
1010
+ f, fp = proc {|x| x**3 + x - 15}, proc {|x| 3*x**2 + 1}
1011
+ s = Interval[-1.0,5.0].newton(f,fp)
1012
+ assert_solution(s, f, Interval[5249383869325654 * 2.0 ** -51])
1013
+ end
1014
+
1015
+ def test_cubic_3
1016
+ f, fp = proc {|x| x * (x ** 2 - 1)}, proc {|x| 3*x**2 - 1}
1017
+ s = Interval[-5.0,5.0].newton(f,fp)
1018
+ assert_solution(s, f, Interval[[-1],[0],[1]])
1019
+ end
1020
+
1021
+ def test_dennis_schnabel
1022
+ f1 = proc {|x| (((x-12) * x + 47 ) * x - 60 )* x}
1023
+ f2 = proc {|x| f1.call(x) + 24 }
1024
+ f3 = proc {|x| f1.call(x) + 24.1 }
1025
+ fp = proc {|x| ((4 * x - 12*3) * x + 47*2) * x - 60}
1026
+
1027
+ assert_solution(Interval[-1e2,1e2].newton(f1,fp), f1, Interval[[0],[3],[4],[5]],:weak)
1028
+ assert_solution(Interval[-1e2,1e2].newton(f2,fp), f2, Interval[[0.888305779071752],[1]], :weak)
1029
+ assert_equal(Interval[], Interval[-1e2,1e2].newton(f3,fp))
1030
+ end
1031
+
1032
+ if FPU.respond_to?(:exp_up)
1033
+ def test_exp
1034
+ f, fp = proc{|x| x.exp + x}, proc {|x| x.exp + 1}
1035
+ z0 = Interval[-1e2,1e2].newton(f,fp)
1036
+ assert_solution(z0, f, Interval[-0.56714329040978384])
1037
+
1038
+ f, fp = proc{|x| x*(-x).exp + 1}, proc {|x| (1-x)*(-x).exp}
1039
+ z1 = Interval[-1e2,1e2].newton(f,fp)
1040
+ assert_solution(z0, f, z0, :weak)
1041
+ assert_sharp(z1)
1042
+ end end
1043
+
1044
+ if FPU.respond_to?(:exp_up)
1045
+ def test_trig
1046
+ f = proc{|x| (x*Interval::PI/3.0).cos() -0.5}
1047
+ fp = proc{|x| -(x*Interval::PI/3).sin() * Interval::PI/3}
1048
+ s = Interval[-10.0,10.0].newton(f, fp)
1049
+ assert_solution(s, f, Interval[[-7], [-5], [-1], [1], [5], [7]], :weak)
1050
+ end end
1051
+
1052
+ end
1053
+
1054
+ if FPU.respond_to?(:exp_up)
1055
+ # Tests Interval transcendental functions.
1056
+ class Interval::TestTranscendental < Test::Unit::TestCase
1057
+ include Interval::Assertions
1058
+
1059
+ def test_exp
1060
+ assert_equal(Interval::E, Interval[1].exp)
1061
+ assert_equal(Interval[1,Interval::E.sup], Interval[0,1].exp)
1062
+ assert_equal(Interval[Interval::E.inf, Infinity], Interval[1,Infinity].exp)
1063
+ assert_equal(Interval[0], Interval[-Infinity].exp)
1064
+ assert_equal(Interval[[0, 1], [Math::E, Infinity]], Interval[[-Infinity,0],[1,Infinity]].exp)
1065
+ end
1066
+
1067
+ def test_log
1068
+ assert_equal(Interval[-Infinity, 0], Interval[-1,+1].log)
1069
+ assert_equal(Interval[0], Interval[1].log)
1070
+ assert_equal(Interval[], Interval[-2,-1].log)
1071
+ assert_equal(Interval[-Infinity], Interval[-2,0].log)
1072
+ assert_equal(Interval[-Infinity,0], Interval[0,1].log)
1073
+ assert(Interval::E.log.include?(1))
1074
+ assert_equal(3 * 2 ** -53, Interval[1].exp.log.width)
1075
+ end
1076
+
1077
+ def test_atan
1078
+ assert_equal(Interval::PI, 4 * Interval[1].atan)
1079
+ assert_equal(Interval[-Interval::PI.sup, Interval::PI.sup], 2 * Interval[-Infinity,Infinity].atan)
1080
+ assert_equal(Interval[0], Interval[0].atan)
1081
+ end
1082
+
1083
+ def test_cosh
1084
+ assert(Interval[1].cosh.sharp?)
1085
+ assert_equal(Interval[1], Interval[0].cosh)
1086
+ assert_equal((Interval[1].cosh | Interval[3].cosh).hull, Interval[1,3].cosh)
1087
+ assert_equal(Interval[1,3].cosh, Interval[-3,-1].cosh)
1088
+ assert_equal((Interval[0] | Interval[3].cosh).hull, Interval[-1,3].cosh)
1089
+ assert_equal(Interval[-1,3].cosh, Interval[-3,1].cosh)
1090
+ assert_equal(Interval[0, Infinity], Interval[-Infinity,Infinity].cosh)
1091
+ end
1092
+
1093
+ def test_sinh
1094
+ assert(Interval[1].sinh.sharp?)
1095
+ assert_equal(Interval[0], Interval[0].sinh)
1096
+ assert_equal((Interval[-1].sinh | Interval[3].sinh).hull, Interval[-1,3].sinh)
1097
+ assert_equal(Interval[-Infinity, Infinity], Interval[-Infinity,Infinity].sinh)
1098
+ end
1099
+
1100
+ def test_cos
1101
+ assert_equal(Interval[-1,-1 + 2 ** -53], Interval::PI.cos)
1102
+ assert_equal(Interval[1 - 2 ** -53, 1], (2*Interval::PI).cos)
1103
+ assert_equal(Interval[-1,1], Interval[Infinity].cos)
1104
+ assert_equal(Interval[-1,1], Interval[-Infinity].cos)
1105
+ onehalf = (Interval::PI/3).cos
1106
+ assert( onehalf.include?(0.5))
1107
+ assert_equal(Interval[onehalf.inf,1], (-Interval::PI/4 | Interval::PI/3).hull.cos)
1108
+ minusonehalf = (2*Interval::PI/3).cos
1109
+ assert(minusonehalf.include?(-0.5))
1110
+ assert_equal(Interval[-1,minusonehalf.sup], (5*Interval::PI/4 | 2*Interval::PI/3).hull.cos)
1111
+ assert_equal((minusonehalf | onehalf).hull, ((Interval::PI | 2*Interval::PI).hull/3).cos)
1112
+ full = (5 * Interval::PI/3 | 3.5 * Interval::PI).hull
1113
+ assert_equal(Interval[-1,1], full.cos)
1114
+ assert_equal(Interval[-1,1], (full + 2 * Interval::PI).cos)
1115
+ assert_equal(Interval[-1,1], (full + 4 * Interval::PI).cos)
1116
+ assert_equal(Interval[-1,1], (full + 6 * Interval::PI).cos)
1117
+ assert_equal(Interval[-1,1], (full + 8 * Interval::PI).cos)
1118
+ assert_equal(Interval[-1,1], (full - 2 * Interval::PI).cos)
1119
+ assert_equal(Interval[-1,1], (full - 4 * Interval::PI).cos)
1120
+ assert_equal(Interval[-1,1], (full - 6 * Interval::PI).cos)
1121
+ assert_equal(Interval[-1,1], (full - 8 * Interval::PI).cos)
1122
+ end
1123
+
1124
+ def test_sin
1125
+ assert_equal(Interval[-1,-1 + 2 ** -53], (3*Interval::PI/2).sin)
1126
+ assert_equal(Interval[1 - 2 ** -53, 1], (Interval::PI/2).sin)
1127
+ assert_equal(Interval[-1,1], Interval[Infinity].sin)
1128
+ assert_equal(Interval[-1,1], Interval[-Infinity].sin)
1129
+ onehalf = (Interval::PI/6).sin
1130
+ assert( onehalf.include?(0.5))
1131
+ assert_equal(Interval[onehalf.inf,1], (3 * Interval::PI/4 | Interval::PI/6).hull.sin)
1132
+ minusonehalf = (7*Interval::PI/6).sin
1133
+ assert(minusonehalf.include?(-0.5))
1134
+ assert_equal(Interval[-1,minusonehalf.sup], (7*Interval::PI/4 | 7*Interval::PI/6).hull.sin)
1135
+ assert_equal((-onehalf | onehalf).hull, ((Interval::PI | -Interval::PI).hull/6.0).sin)
1136
+ full = ((5 * Interval::PI/3 | 3.5 * Interval::PI) + Interval::PI/2).hull
1137
+ assert_equal(Interval[-1,1], full.sin)
1138
+ assert_equal(Interval[-1,1], (full + 2 * Interval::PI).cos)
1139
+ assert_equal(Interval[-1,1], (full + 4 * Interval::PI).cos)
1140
+ assert_equal(Interval[-1,1], (full + 6 * Interval::PI).cos)
1141
+ assert_equal(Interval[-1,1], (full + 8 * Interval::PI).cos)
1142
+ assert_equal(Interval[-1,1], (full - 2 * Interval::PI).cos)
1143
+ assert_equal(Interval[-1,1], (full - 4 * Interval::PI).cos)
1144
+ assert_equal(Interval[-1,1], (full - 6 * Interval::PI).cos)
1145
+ assert_equal(Interval[-1,1], (full - 8 * Interval::PI).cos)
1146
+ end
1147
+
1148
+ def test_tan
1149
+ assert_equal(Interval[0], Interval[0].tan)
1150
+ assert_equal(Interval[], Interval[].tan)
1151
+ assert_equal(Interval[-Infinity, Infinity], Interval[0,6].tan)
1152
+ assert_equal(Interval[-Infinity, Infinity], (-Interval::PI/2 | Interval::PI/2).hull.tan)
1153
+ assert_equal(Interval[-Infinity, Infinity], (- Interval::PI/4 | Interval::PI * 1.25).hull.tan)
1154
+ assert_equal(Interval[-Infinity, Infinity], (4.75 *Interval::PI | Interval::PI * 6.25).hull.tan)
1155
+
1156
+ assert_equal(2 ** -51, Interval::PI.tan.width)
1157
+ assert(Interval::PI.tan.include?(0))
1158
+ assert_equal(3 * 2 ** -53, (Interval::PI/4).tan.width)
1159
+ assert((Interval::PI/4).tan.include?(1) )
1160
+
1161
+ x = (Interval::PI/4 | Interval::PI * 0.75).hull
1162
+ assert_equal((Interval[x.sup].tan | -Infinity).hull | (Interval[x.inf].tan | Infinity).hull, x.tan)
1163
+
1164
+ x = (Interval::PI | -Interval::PI).hull/4
1165
+ assert_equal((Interval[x.inf].tan | Interval[x.sup].tan).hull, x.tan)
1166
+ end
1167
+
1168
+ end end
1169
+
1170
+ Test::Unit.run = (__FILE__ != $0)