intervals 0.3.56

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.
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)