mdarray 0.5.0.pre-java → 0.5.3-java

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 (42) hide show
  1. data/README.md +89 -90
  2. data/Rakefile +6 -1
  3. data/lib/colt/cern_double_functions.rb +193 -0
  4. data/lib/colt/cern_float_functions.rb +193 -0
  5. data/lib/colt/cern_int_functions.rb +152 -0
  6. data/lib/colt/cern_long_functions.rb +152 -0
  7. data/lib/colt/colt.rb +103 -1
  8. data/lib/mdarray.rb +71 -23
  9. data/lib/mdarray/access.rb +8 -0
  10. data/lib/mdarray/counter.rb +43 -1
  11. data/lib/mdarray/creation.rb +5 -10
  12. data/lib/mdarray/fast_operators.rb +17 -13
  13. data/lib/mdarray/function_creation.rb +11 -45
  14. data/lib/mdarray/function_map.rb +16 -8
  15. data/lib/mdarray/lazy_mdarray.rb +311 -0
  16. data/lib/mdarray/lazy_operators.rb +166 -0
  17. data/lib/mdarray/operators.rb +38 -9
  18. data/lib/mdarray/proc_util.rb +2 -0
  19. data/lib/mdarray/ruby_boolean_functions.rb +24 -0
  20. data/lib/mdarray/ruby_functions.rb +76 -2
  21. data/lib/mdarray/ruby_generic_functions.rb +12 -4
  22. data/lib/mdarray/ruby_math.rb +180 -2
  23. data/lib/mdarray/ruby_numeric_functions.rb +198 -7
  24. data/target/helper.jar +0 -0
  25. data/test/colt/ColtMethods.xlsx +0 -0
  26. data/test/colt/test_complete.rb +1 -0
  27. data/test/colt/test_math.rb +249 -0
  28. data/test/complete.rb +1 -0
  29. data/test/env.rb +17 -4
  30. data/test/mdarray/arithmetic_casting.rb +3 -0
  31. data/test/mdarray/test_boolean.rb +1 -1
  32. data/test/mdarray/test_complete.rb +1 -0
  33. data/test/mdarray/test_error.rb +13 -13
  34. data/test/mdarray/test_lazy.rb +306 -0
  35. data/test/mdarray/test_operator.rb +1 -1
  36. data/test/mdarray/test_performance.rb +57 -4
  37. data/test/mdarray/test_trigonometry.rb +5 -1
  38. data/vendor/commons-compiler.jar +0 -0
  39. data/vendor/janino.jar +0 -0
  40. data/version.rb +1 -1
  41. metadata +47 -10
  42. data/test/mdarray/test_statistics.rb +0 -80
@@ -0,0 +1,166 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ##########################################################################################
4
+ # Copyright © 2013 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify,
5
+ # and distribute this software and its documentation for educational, research, and
6
+ # not-for-profit purposes, without fee and without a signed licensing agreement, is hereby
7
+ # granted, provided that the above copyright notice, this paragraph and the following two
8
+ # paragraphs appear in all copies, modifications, and distributions. Contact Rodrigo
9
+ # Botafogo - rodrigo.a.botafogo@gmail.com for commercial licensing opportunities.
10
+ #
11
+ # IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
12
+ # INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
13
+ # THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE
14
+ # POSSIBILITY OF SUCH DAMAGE.
15
+ #
16
+ # RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
18
+ # SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
19
+ # RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
20
+ # OR MODIFICATIONS.
21
+ ##########################################################################################
22
+
23
+ ##########################################################################################
24
+ #
25
+ ##########################################################################################
26
+
27
+ class LazyBinaryOperator < BinaryOperator
28
+
29
+ #---------------------------------------------------------------------------------------
30
+ #
31
+ #---------------------------------------------------------------------------------------
32
+
33
+ def get_args(*args)
34
+
35
+ @op1 = args.shift
36
+ @op2 = args.shift
37
+ @other_args = args
38
+
39
+ end
40
+
41
+ #---------------------------------------------------------------------------------------
42
+ # A default binary operator takes two arrays where one array can be degenerated (a
43
+ # number and loops through all elements of the arrays applying a given method to them.
44
+ # For instance, operator '+' in a + b is a default binary operator.
45
+ #---------------------------------------------------------------------------------------
46
+
47
+ def default(*args)
48
+
49
+ get_args(*args)
50
+ lazy = @op1
51
+
52
+ if (@op1.is_a? LazyMDArray)
53
+ lazy.push(@op2)
54
+ lazy.push(self)
55
+ else
56
+ lazy = LazyMDArray.new
57
+ lazy.push(@op1)
58
+ lazy.push(@op2)
59
+ lazy.push(self)
60
+ end
61
+
62
+ return lazy
63
+
64
+ end
65
+
66
+ #---------------------------------------------------------------------------------------
67
+ # A fill binary operator takes two arrays where one array can be degenerated (a number)
68
+ # and loops through all elements of the arrays, setting the value of the first array
69
+ # to the values of the second.
70
+ #---------------------------------------------------------------------------------------
71
+
72
+ def fill(*args)
73
+ raise "Cannot fill array lazyly"
74
+ end
75
+
76
+ #---------------------------------------------------------------------------------------
77
+ #
78
+ #---------------------------------------------------------------------------------------
79
+
80
+ def in_place(*args)
81
+ raise "Cannot operate in_place lazyly"
82
+ end
83
+
84
+ #---------------------------------------------------------------------------------------
85
+ #
86
+ #---------------------------------------------------------------------------------------
87
+
88
+ def reduce(*args)
89
+ raise "Cannot reduce array in lazy operation"
90
+ end
91
+
92
+ #---------------------------------------------------------------------------------------
93
+ #
94
+ #---------------------------------------------------------------------------------------
95
+
96
+ def complex_reduce(*args)
97
+ raise "Cannot reduce array in lazy operation"
98
+ end
99
+
100
+ end # LazyBinaryOperator
101
+
102
+ ##########################################################################################
103
+ #
104
+ ##########################################################################################
105
+
106
+ class LazyUnaryOperator < UnaryOperator
107
+
108
+ #---------------------------------------------------------------------------------------
109
+ #
110
+ #---------------------------------------------------------------------------------------
111
+
112
+ def get_args(*args)
113
+
114
+ @op = args.shift
115
+ @other_args = args
116
+
117
+ end
118
+
119
+ #---------------------------------------------------------------------------------------
120
+ # A default unary operator takes one arrays and loops through all elements of the array
121
+ # applying a given method to it. For instance, operator 'log' in a.log is a default
122
+ # unary operator.
123
+ #---------------------------------------------------------------------------------------
124
+
125
+ def default(*args)
126
+
127
+ get_args(*args)
128
+ lazy = @op
129
+
130
+ if (@op.is_a? LazyMDArray)
131
+ lazy.push(self)
132
+ else
133
+ lazy = LazyMDArray.new
134
+ lazy.push(@op)
135
+ lazy.push(self)
136
+ end
137
+
138
+ return lazy
139
+
140
+ end
141
+
142
+ #---------------------------------------------------------------------------------------
143
+ #
144
+ #---------------------------------------------------------------------------------------
145
+
146
+ def in_place(*args)
147
+ raise "Cannot operate in_place lazyly"
148
+ end
149
+
150
+ #---------------------------------------------------------------------------------------
151
+ #
152
+ #---------------------------------------------------------------------------------------
153
+
154
+ def reduce(*args)
155
+ raise "Cannot reduce array in lazy operation"
156
+ end
157
+
158
+ #---------------------------------------------------------------------------------------
159
+ #
160
+ #---------------------------------------------------------------------------------------
161
+
162
+ def complex_reduce(*args)
163
+ raise "Cannot reduce array in lazy operation"
164
+ end
165
+
166
+ end # LazyUnaryOperator
@@ -52,6 +52,14 @@ class Const
52
52
  #
53
53
  #---------------------------------------------------------------------------------------
54
54
 
55
+ def get(index)
56
+ @value
57
+ end
58
+
59
+ #---------------------------------------------------------------------------------------
60
+ #
61
+ #---------------------------------------------------------------------------------------
62
+
55
63
  def get_next
56
64
  @value
57
65
  end
@@ -73,12 +81,15 @@ end # Const
73
81
  class Operator
74
82
 
75
83
  attr_reader :name
76
- attr_reader :type # resulting type of the operation
77
- attr_reader :arity # number of arguments to the operator
84
+ attr_reader :type # resulting type of the operation
85
+ attr_reader :arity # number of arguments to the operator
78
86
  attr_reader :exec_type # type of operator execution, e.g., default, in_place, numeric
79
- attr_reader :force_type # force this type as the result type
80
- attr_reader :pre_condition # proc to be executed before the operator's execution
87
+ attr_reader :helper # helper method for this operator
88
+ attr_reader :fmap # function map for this operator
89
+ attr_reader :force_type # force this type as the result type
90
+ attr_reader :pre_condition # proc to be executed before the operator's execution
81
91
  attr_reader :post_condition # proc to be executed after the operator's execution
92
+ attr_reader :other_args # list of arguments to the operator other than the operands
82
93
 
83
94
  #---------------------------------------------------------------------------------------
84
95
  #
@@ -90,6 +101,7 @@ class Operator
90
101
  @name = name
91
102
  @arity = arity
92
103
  @exec_type = exec_type
104
+ @helper = nil
93
105
  @force_type = force_type
94
106
  @pre_condition = pre_condition # proc to be executed before the main loop
95
107
  @pre_condition_result = nil
@@ -181,12 +193,23 @@ class BinaryOperator < Operator
181
193
  requested_type = args.shift
182
194
  @type = (@force_type)? @force_type : (requested_type)? requested_type : get_type
183
195
  @coerced = @op1.coerced
184
- func = MDArray.select_function(@name, MDArray.functions, @type)
185
- if (func.is_a? Proc)
186
- @do_func = func.dup
196
+
197
+ # select_function could use information about the input1 and input2 arguments
198
+ # but if the operation is cast to the higher type @type and we don't have yet
199
+ # functions that have different types of arguments for operators, then just
200
+ # use the higher type. This is different for comparison operators in which the
201
+ # return type is boolean and the input types are numeric.
202
+ if (MDArray.numerical.include?(@type))
203
+ fmap = MDArray.select_function(@name, MDArray.functions, @type, @type, @type)
187
204
  else
188
- @do_func = func
205
+ fmap = MDArray.select_function(@name, MDArray.functions, @type, @op1.type, @op1.type)
189
206
  end
207
+
208
+ # func = fmap.function
209
+ @helper = fmap.helper
210
+ @fmap = fmap
211
+ # @do_func = func.dup
212
+ @do_func = (fmap.function).dup
190
213
  @other_args = args
191
214
 
192
215
  end
@@ -257,14 +280,20 @@ class UnaryOperator < Operator
257
280
  def parse_args(*args)
258
281
 
259
282
  @op = args.shift
283
+
260
284
  requested_type = args.shift
261
285
  @type = (@force_type)? @force_type : (requested_type)? requested_type : @op.type
262
- func = MDArray.select_function(@name, MDArray.functions, @type)
286
+
287
+ fmap = MDArray.select_function(@name, MDArray.functions, @type, @type, "void")
288
+ func = fmap.function
289
+ @helper = fmap.helper
290
+
263
291
  if (func.is_a? Proc)
264
292
  @do_func = func.dup
265
293
  else
266
294
  @do_func = func
267
295
  end
296
+
268
297
  @other_args = args
269
298
 
270
299
  end
@@ -154,6 +154,8 @@ class Proc
154
154
  lambda { |arg| return arg }
155
155
  end
156
156
 
157
+ alias :apply :call
158
+
157
159
  end # Proc
158
160
 
159
161
 
@@ -7,9 +7,33 @@ module BooleanFunctions
7
7
  extend FunctionCreation
8
8
  extend RubyFunctions
9
9
 
10
+ class And
11
+ def self.apply(val1, val2)
12
+ val1 and val2
13
+ end
14
+ end
15
+
16
+ class Or
17
+ def self.apply(val1, val2)
18
+ val1 or val2
19
+ end
20
+ end
21
+
22
+ class Not
23
+ def self.apply(val)
24
+ !val
25
+ end
26
+ end
27
+
28
+ @and = BooleanFunctions::And
29
+ @or = BooleanFunctions::Or
30
+ @not = BooleanFunctions::Not
31
+
32
+ =begin
10
33
  @and = Proc.new { |val1, val2| val1 and val2 }
11
34
  @or = Proc.new { |val1, val2| val1 or val2 }
12
35
  @not = Proc.new { |val1| !val1}
36
+ =end
13
37
 
14
38
  @binary_methods = [:and, :or]
15
39
 
@@ -25,10 +25,80 @@
25
25
 
26
26
  module RubyFunctions
27
27
 
28
+ class << self
29
+ attr_reader :binary_helper
30
+ attr_reader :unary_helper
31
+ end
32
+
33
+ @binary_helper = Java::RbMdarrayLoopsBinops
34
+ @unary_helper = Java::RbMdarrayLoopsUnops
35
+
36
+ #------------------------------------------------------------------------------------
37
+ #
38
+ #------------------------------------------------------------------------------------
39
+
40
+ def make_binary_operators(name, func, default = true, in_place = true)
41
+
42
+ if (default)
43
+ make_binary_op(name, :default, func, RubyFunctions.binary_helper)
44
+ end
45
+ if (in_place)
46
+ make_binary_op(name + "!", :in_place, func, RubyFunctions.binary_helper)
47
+ end
48
+
49
+ end
50
+
51
+ #------------------------------------------------------------------------------------
52
+ #
53
+ #------------------------------------------------------------------------------------
54
+
55
+ def make_binary_operator(name, type, func)
56
+ make_binary_op(name, type, func, RubyFunctions.binary_helper)
57
+ end
58
+
59
+ #------------------------------------------------------------------------------------
60
+ #
61
+ #------------------------------------------------------------------------------------
62
+
63
+ def make_unary_operators(name, func, default = true, in_place = true)
64
+
65
+ if (default)
66
+ make_unary_op(name, :default, func, RubyFunctions.unary_helper)
67
+ end
68
+ if (in_place)
69
+ make_unary_op(name + "!", :in_place, func, RubyFunctions.unary_helper)
70
+ end
71
+
72
+ end
73
+
74
+ #------------------------------------------------------------------------------------
75
+ #
76
+ #------------------------------------------------------------------------------------
77
+
78
+ def make_unary_operator(name, type, func)
79
+ make_unary_op(name, type, func, RubyFunctions.unary_helper)
80
+ end
81
+
82
+ #------------------------------------------------------------------------------------
83
+ #
84
+ #------------------------------------------------------------------------------------
85
+
86
+ def make_comparison_operator(name, func)
87
+ make_binary_op(name, "default", func, RubyFunctions.binary_helper, "boolean")
88
+ end
89
+
90
+ #------------------------------------------------------------------------------------
91
+ #
92
+ #------------------------------------------------------------------------------------
93
+
28
94
  def ruby_binary_function(long_name, proc)
29
95
  [long_name, "RubyFunctions", proc, "*", "*", "*"]
30
96
  end
31
97
 
98
+ #------------------------------------------------------------------------------------
99
+ #
100
+ #------------------------------------------------------------------------------------
101
+
32
102
  def ruby_unary_function(long_name, proc)
33
103
  [long_name, "RubyFunctions", proc, "*", "*", "*"]
34
104
  end
@@ -52,7 +122,8 @@ module UserFunction
52
122
 
53
123
  function = ruby_binary_function("#{name}_user", func)
54
124
  klass = Object.const_get("#{where.capitalize}MDArray")
55
- klass.make_binary_op(name, exec_type, function, force_type, pre_condition, post_condition)
125
+ klass.make_binary_op(name, exec_type, function, RubyFunctions.binary_helper,
126
+ force_type, pre_condition, post_condition)
56
127
 
57
128
  end
58
129
 
@@ -66,7 +137,8 @@ module UserFunction
66
137
 
67
138
  function = ruby_unary_function("#{name}_user", func)
68
139
  klass = Object.const_get("#{where.capitalize}MDArray")
69
- klass.make_unary_op(name, exec_type, function, force_type, pre_condition, post_condition)
140
+ klass.make_unary_op(name, exec_type, function, RubyFunctions.unary_helper, force_type,
141
+ pre_condition, post_condition)
70
142
 
71
143
  end
72
144
 
@@ -77,3 +149,5 @@ require_relative 'ruby_numeric_functions'
77
149
  require_relative 'ruby_math'
78
150
  require_relative 'ruby_boolean_functions'
79
151
  require_relative 'ruby_stats'
152
+
153
+ MDArray.functions = "RubyFunctions"
@@ -7,22 +7,30 @@ module GenericFunctions
7
7
  extend FunctionCreation
8
8
  extend RubyFunctions
9
9
 
10
+ class Null
11
+ def self.apply
12
+ end
13
+ end
14
+
15
+ @null = GenericFunctions::Null
16
+
17
+ =begin
10
18
  @null = Proc.new { }
19
+ =end
11
20
 
12
21
  #---------------------------------------------------------------------------------------
13
22
  #
14
23
  #---------------------------------------------------------------------------------------
15
24
 
16
- make_unary_op("dim_set", :set_block,
25
+ make_unary_operator("dim_set", :set_block,
17
26
  ["ruby_dim_set", "RubyFunctions", @null, "*", "*", "void"])
18
27
 
19
28
  #---------------------------------------------------------------------------------------
20
29
  #
21
30
  #---------------------------------------------------------------------------------------
22
31
 
23
- make_binary_op("fill", :fill,
24
- ["ruby_fill", "RubyFunctions", @null, "*", "*", "void"])
25
-
32
+ make_binary_operator("fill", :fill,
33
+ ["ruby_fill", "RubyFunctions", @null, "*", "*", "*"])
26
34
 
27
35
  end # GenericFunctions
28
36
 
@@ -5,7 +5,184 @@
5
5
  module RubyMath
6
6
  extend FunctionCreation
7
7
  extend RubyFunctions
8
-
8
+
9
+ class Acos
10
+ def self.apply(val)
11
+ Math.acos(val)
12
+ end
13
+ end
14
+
15
+ class Acosh
16
+ def self.apply(val)
17
+ Math.acosh(val)
18
+ end
19
+ end
20
+
21
+ class Asin
22
+ def self.apply(val)
23
+ Math.asin(val)
24
+ end
25
+ end
26
+
27
+ class Asinh
28
+ def self.apply(val)
29
+ Math.asinh(val)
30
+ end
31
+ end
32
+
33
+ class Atan
34
+ def self.apply(val)
35
+ Math.atan(val)
36
+ end
37
+ end
38
+
39
+ class Atan2
40
+ def self.apply(val)
41
+ Math.atan2(val)
42
+ end
43
+ end
44
+
45
+ class Atanh
46
+ def self.apply(val)
47
+ Math.atanh(val)
48
+ end
49
+ end
50
+
51
+ class Cbrt
52
+ def self.apply(val)
53
+ Math.cbrt(val)
54
+ end
55
+ end
56
+
57
+ class Cos
58
+ def self.apply(val)
59
+ Math.cos(val)
60
+ end
61
+ end
62
+
63
+ class Cosh
64
+ def self.apply(val)
65
+ Math.cosh(val)
66
+ end
67
+ end
68
+
69
+ class Erf
70
+ def self.apply(val)
71
+ Math.erf(val)
72
+ end
73
+ end
74
+
75
+ class Erfc
76
+ def self.apply(val)
77
+ Math.erfc(val)
78
+ end
79
+ end
80
+
81
+ class Exp
82
+ def self.apply(val)
83
+ Math.exp(val)
84
+ end
85
+ end
86
+
87
+ class Gamma
88
+ def self.apply(val)
89
+ Math.gamma(val)
90
+ end
91
+ end
92
+
93
+ class Hypot
94
+ def self.apply(val)
95
+ Math.hypot(val)
96
+ end
97
+ end
98
+
99
+ class Ldexp
100
+ def self.apply(val)
101
+ Math.ldexp(val)
102
+ end
103
+ end
104
+
105
+ class Log
106
+ def self.apply(val)
107
+ Math.log(val)
108
+ end
109
+ end
110
+
111
+ class Log10
112
+ def self.apply(val)
113
+ Math.log10(val)
114
+ end
115
+ end
116
+
117
+ class Log2
118
+ def self.apply(val)
119
+ Math.log2(val)
120
+ end
121
+ end
122
+
123
+ class Sin
124
+ def self.apply(val)
125
+ Math.sin(val)
126
+ end
127
+ end
128
+
129
+ class Sinh
130
+ def self.apply(val)
131
+ Math.sinh(val)
132
+ end
133
+ end
134
+
135
+ class Sqrt
136
+ def self.apply(val)
137
+ Math.sqrt(val)
138
+ end
139
+ end
140
+
141
+ class Tan
142
+ def self.apply(val)
143
+ Math.tan(val)
144
+ end
145
+ end
146
+
147
+ class Tanh
148
+ def self.apply(val)
149
+ Math.tanh(val)
150
+ end
151
+ end
152
+
153
+ class Neg
154
+ def self.apply(val)
155
+ -1 * val
156
+ end
157
+ end
158
+
159
+ @acos = RubyMath::Acos
160
+ @acosh = RubyMath::Acosh
161
+ @asin = RubyMath::Asin
162
+ @asinh = RubyMath::Asinh
163
+ @atan = RubyMath::Atan
164
+ @atan2 = RubyMath::Atan2
165
+ @atanh = RubyMath::Atanh
166
+ @cbrt = RubyMath::Cbrt
167
+ @cos = RubyMath::Cos
168
+ @cosh = RubyMath::Cosh
169
+ @erf = RubyMath::Erf
170
+ @erfc = RubyMath::Erfc
171
+ @exp = RubyMath::Exp
172
+ @gamma = RubyMath::Gamma
173
+ @hypot = RubyMath::Hypot
174
+ @ldexp = RubyMath::Ldexp
175
+ @log = RubyMath::Log
176
+ @log10 = RubyMath::Log10
177
+ @log2 = RubyMath::Log2
178
+ @sin = RubyMath::Sin
179
+ @sinh = RubyMath::Sinh
180
+ @sqrt = RubyMath::Sqrt
181
+ @tan = RubyMath::Tan
182
+ @tanh = RubyMath::Tanh
183
+ @neg = RubyMath::Neg
184
+
185
+ =begin
9
186
  @acos = Proc.new { |val| Math.acos(val) }
10
187
  @acosh = Proc.new { |val| Math.acosh(val) }
11
188
  @asin = Proc.new { |val| Math.asin(val) }
@@ -20,7 +197,7 @@ module RubyMath
20
197
  @erfc = Proc.new { |val| Math.erfc(val) }
21
198
  @exp = Proc.new { |val| Math.exp(val) }
22
199
  @gamma = Proc.new { |val| Math.gamma(val) }
23
- @hypot = Proc.new { |val| Math.hypotn(val) }
200
+ @hypot = Proc.new { |val| Math.hypot(val) }
24
201
  @ldexp = Proc.new { |val| Math.ldexp(val) }
25
202
  @log = Proc.new { |val| Math.log(val) }
26
203
  @log10 = Proc.new { |val| Math.log10(val) }
@@ -31,6 +208,7 @@ module RubyMath
31
208
  @tan = Proc.new { |val| Math.tan(val) }
32
209
  @tanh = Proc.new { |val| Math.tanh(val) }
33
210
  @neg = Proc.new { |val| -1 * val }
211
+ =end
34
212
 
35
213
  @unary_methods = [:acos, :acosh, :asin, :asinh, :atan, :atan2,
36
214
  :atanh, :cbrt, :cos, :erf, :exp, :gamma, :hypot, :ldexp,