1
+ import numpy_quaddtype as npq
2
+ import numpy as np
3
+
4
+
5
+ def test_scalar_ops (backend ):
6
+ print (f"\n Testing scalar operations for{ backend } backend:" )
7
+
8
+ # Create QuadPrecision instances
9
+ q1 = npq .QuadPrecision (
10
+ "3.14159265358979323846264338327950288" ,backend = backend )
11
+ q2 = npq .QuadPrecision (
12
+ "-2.71828182845904523536028747135266250" ,backend = backend )
13
+
14
+ # Test unary operations
15
+ print ("\n Unary operations:" )
16
+ print (f" Negation of q1:{ - q1 } " )
17
+ print (f" Absolute value of q2:{ abs (q2 )} " )
18
+
19
+ # Test binary operations
20
+ print ("\n Binary operations:" )
21
+ print (f" Addition:{ q1 + q2 } " )
22
+ print (f" Subtraction:{ q1 - q2 } " )
23
+ print (f" Multiplication:{ q1 * q2 } " )
24
+ print (f" Division:{ q1 / q2 } " )
25
+
26
+ # Test comparison operations
27
+ print ("\n Comparison operations:" )
28
+ print (f" q1 == q2:{ q1 == q2 } " )
29
+ print (f" q1 != q2:{ q1 != q2 } " )
30
+ print (f" q1 < q2:{ q1 < q2 } " )
31
+ print (f" q1 <= q2:{ q1 <= q2 } " )
32
+ print (f" q1 > q2:{ q1 > q2 } " )
33
+ print (f" q1 >= q2:{ q1 >= q2 } " )
34
+
35
+ # Test operations with Python numbers
36
+ print ("\n Operations with Python numbers:" )
37
+ print (f" q1 + 1:{ q1 + 1 } " )
38
+ print (f" q1 - 2.5:{ q1 - 2.5 } " )
39
+ print (f" q1 * 3:{ q1 * 3 } " )
40
+ print (f" q1 / 2:{ q1 / 2 } " )
41
+
42
+ # Test boolean conversion
43
+ print ("\n Boolean conversion:" )
44
+ print (f" bool(q1):{ np .bool (q1 )} " )
45
+ print (
46
+ f" bool(npq.QuadPrecision('0', backend=backend)):{ np .bool (npq .QuadPrecision ('0' ,backend = backend ))} " )
47
+
48
+
49
+ def test_casting (backend ):
50
+ print (f"\n Testing{ backend } backend:" )
51
+
52
+ # Create QuadPrecision instances
53
+ q1 = npq .QuadPrecision (
54
+ "3.14159265358979323846264338327950288" ,backend = backend )
55
+ q2 = npq .QuadPrecision (
56
+ "-2.71828182845904523536028747135266250" ,backend = backend )
57
+
58
+ # Test casting from QuadPrecision to numpy dtypes
59
+ print ("Casting from QuadPrecision to numpy dtypes:" )
60
+ print (f" float32:{ np .float32 (q1 )} " )
61
+ print (f" float64:{ np .float64 (q1 )} " )
62
+ print (f" int64:{ np .int64 (q1 )} " )
63
+ print (f" uint64:{ np .uint64 (q1 )} " )
64
+
65
+ # Test casting from numpy dtypes to QuadPrecision
66
+ print ("\n Casting from numpy dtypes to QuadPrecision:" )
67
+ print (
68
+ f" float32:{ np .float32 (3.14159 ).astype (npq .QuadPrecDType (backend = backend ))} " )
69
+ print (
70
+ f" float64:{ np .float64 (2.71828182845904 ).astype (npq .QuadPrecDType (backend = backend ))} " )
71
+ print (
72
+ f" int64:{ np .int64 (- 1234567890 ).astype (npq .QuadPrecDType (backend = backend ))} " )
73
+ print (
74
+ f" uint64:{ np .uint64 (9876543210 ).astype (npq .QuadPrecDType (backend = backend ))} " )
75
+
76
+ # Test array operations
77
+ print ("\n Array operations:" )
78
+ q_array = np .array ([q1 ,q2 ],dtype = npq .QuadPrecDType (backend = backend ))
79
+ print (f" QuadPrecision array:{ q_array } " )
80
+
81
+ np_array = np .array ([3.14 ,- 2.71 ,1.41 ,- 1.73 ],dtype = np .float64 )
82
+ q_from_np = np_array .astype (npq .QuadPrecDType (backend = backend ))
83
+ print (f" Numpy to QuadPrecision:{ q_from_np } " )
84
+
85
+ back_to_np = np .array (q_from_np ,dtype = np .float64 )
86
+ print (f" QuadPrecision to Numpy:{ back_to_np } " )
87
+
88
+ # Test precision maintenance
89
+ large_int = 12345678901234567890
90
+ q_large = np .array ([large_int ],dtype = np .uint64 ).astype (
91
+ npq .QuadPrecDType (backend = backend ))[0 ]
92
+ print (f"\n Precision test:" )
93
+ print (f" Original large int:{ large_int } " )
94
+ print (f" QuadPrecision:{ q_large } " )
95
+ print (f" Back to int:{ np .uint64 (q_large )} " )
96
+
97
+ # Test edge cases
98
+
99
+
100
+ def test_edge_cases (backend ):
101
+ print (f"\n Testing negative numbers for{ backend } backend:" )
102
+
103
+ # Test various negative numbers
104
+ test_values = [
105
+ - 1.0 ,
106
+ - 1e10 ,
107
+ - 1e100 ,
108
+ - 1e300 ,
109
+ np .nextafter (np .finfo (np .float64 ).min ,0 ),
110
+ np .finfo (np .float64 ).min
111
+ ]
112
+
113
+ for value in test_values :
114
+ q_value = npq .QuadPrecision (str (value ),backend = backend )
115
+ print (f" Original:{ value } " )
116
+ print (f" QuadPrecision:{ q_value } " )
117
+ print (f" Back to float64:{ np .float64 (q_value )} " )
118
+ print ()
119
+
120
+ # Test value beyond float64 precision
121
+ beyond_float64_precision = "1.7976931348623157081452742373170435e+308"
122
+ q_beyond = npq .QuadPrecision (beyond_float64_precision ,backend = backend )
123
+ print (f" Beyond float64 precision:{ q_beyond } " )
124
+ q_float64_max = npq .QuadPrecision (
125
+ str (np .finfo (np .float64 ).max ),backend = backend )
126
+ diff = q_beyond - q_float64_max
127
+ print (f" Difference from float64 max:{ diff } " )
128
+ print (
129
+ f" Difference is positive:{ diff > npq .QuadPrecision ('0' ,backend = backend )} " )
130
+
131
+ # Test epsilon (smallest representable difference between two numbers)
132
+ q_epsilon = npq .QuadPrecision (
133
+ str (np .finfo (np .float64 ).eps ),backend = backend )
134
+ print (f" Float64 epsilon in QuadPrecision:{ q_epsilon } " )
135
+ q_one = npq .QuadPrecision ("1" ,backend = backend )
136
+ q_one_plus_epsilon = q_one + q_epsilon
137
+ print (f" 1 + epsilon != 1:{ q_one_plus_epsilon != q_one } " )
138
+ print (f" (1 + epsilon) - 1:{ q_one_plus_epsilon - q_one } " )
139
+
140
+
141
+ def test_ufuncs (backend ):
142
+ print (f"\n Testing ufuncs for{ backend } backend:" )
143
+
144
+ # Create QuadPrecision arrays
145
+ q_array1 = np .array ([1 ,2 ,3 ],dtype = npq .QuadPrecDType (backend = backend ))
146
+ q_array2 = np .array ([1 ,2 ,3 ],dtype = npq .QuadPrecDType (backend = backend ))
147
+
148
+ # Test unary ufuncs
149
+ print ("\n Unary unfuncs:" )
150
+ print (f" negative:{ np .negative (q_array1 )} " )
151
+ print (f" absolute:{ np .absolute (q_array1 )} " )
152
+ print (f" rint:{ np .rint (q_array1 )} " )
153
+ print (f" floor:{ np .floor (q_array1 )} " )
154
+ print (f" ceil:{ np .ceil (q_array1 )} " )
155
+ print (f" trunc:{ np .trunc (q_array1 )} " )
156
+ print (f" sqrt:{ np .sqrt (q_array1 )} " )
157
+ print (f" square:{ np .square (q_array1 )} " )
158
+ print (f" log:{ np .log (q_array1 )} " )
159
+ print (f" log2:{ np .log2 (q_array1 )} " )
160
+ print (f" log10:{ np .log10 (q_array1 )} " )
161
+ print (f" exp:{ np .exp (q_array1 )} " )
162
+ print (f" exp2:{ np .exp2 (q_array1 )} " )
163
+
164
+ # Test binary ufuncs
165
+ print ("\n Binary ufuncs:" )
166
+ print (f" add:{ np .add (q_array1 ,q_array2 )} " )
167
+ print (f" subtract:{ np .subtract (q_array1 ,q_array2 )} " )
168
+ print (f" multiply:{ np .multiply (q_array1 ,q_array2 )} " )
169
+ print (f" divide:{ np .divide (q_array1 ,q_array2 )} " )
170
+ print (f" power:{ np .power (q_array1 ,q_array2 )} " )
171
+ print (f" mod:{ np .mod (q_array1 ,q_array2 )} " )
172
+ print (f" minimum:{ np .minimum (q_array1 ,q_array2 )} " )
173
+ print (f" maximum:{ np .maximum (q_array1 ,q_array2 )} " )
174
+
175
+ # Test comparison ufuncs
176
+ print ("\n Comparison ufuncs:" )
177
+ print (f" equal:{ np .equal (q_array1 ,q_array2 )} " )
178
+ print (f" not_equal:{ np .not_equal (q_array1 ,q_array2 )} " )
179
+ print (f" less:{ np .less (q_array1 ,q_array2 )} " )
180
+ print (f" less_equal:{ np .less_equal (q_array1 ,q_array2 )} " )
181
+ print (f" greater:{ np .greater (q_array1 ,q_array2 )} " )
182
+ print (f" greater_equal:{ np .greater_equal (q_array1 ,q_array2 )} " )
183
+
184
+ # Test mixed operations with numpy arrays
185
+ print (f"Testing backend:{ backend } " )
186
+ print ("\n Mixed operations with numpy arrays:" )
187
+ np_array = np .array ([1.0 ,2.0 ,3.0 ],dtype = np .float64 )
188
+ print (f" add:{ np .add (q_array1 ,np_array )} " )
189
+ print (f" multiply:{ np .multiply (q_array1 ,np_array )} " )
190
+ print (f" divide:{ np .divide (q_array1 ,np_array )} " )
191
+
192
+ # Test reduction operations
193
+ print ("\n Reduction operations:" )
194
+ print (f" sum:{ np .sum (q_array1 )} " )
195
+ print (f" prod:{ np .prod (q_array1 )} " )
196
+ print (f" min:{ np .min (q_array1 )} " )
197
+ print (f" max:{ np .max (q_array1 )} " )
198
+
199
+ from numpy_quaddtype import QuadPrecision ,QuadPrecDType
200
+
201
+ def test_quad_precision ():
202
+ print ("Testing QuadPrecision scalar:" )
203
+
204
+ # Test different initializations
205
+ values = [
206
+ 0 ,
207
+ 1 ,
208
+ - 1 ,
209
+ 3.14159265358979323846 ,
210
+ 1e100 ,
211
+ 1e-100 ,
212
+ float ('inf' ),
213
+ float ('-inf' ),
214
+ float ('nan' )
215
+ ]
216
+
217
+ for val in values :
218
+ q = QuadPrecision (val )
219
+ print (f"Value:{ val } " )
220
+ print (f" str:{ str (q )} " )
221
+ print (f" repr:{ repr (q )} " )
222
+
223
+ # Test different backends
224
+ print ("\n Testing backends:" )
225
+ q_sleef = QuadPrecision (3.14159265358979323846 ,backend = 'sleef' )
226
+ q_longdouble = QuadPrecision (3.14159265358979323846 ,backend = 'longdouble' )
227
+ print (f"Sleef:{ q_sleef } " )
228
+ print (f"Long double:{ q_longdouble } " )
229
+
230
+ def test_quad_dtype ():
231
+ print ("\n Testing QuadPrecDType:" )
232
+
233
+ # Create an array with QuadPrecDType
234
+ arr = np .array ([0 ,1 ,- 1 ,3.14159265358979323846 ,1e100 ,1e-100 ],
235
+ dtype = QuadPrecDType ())
236
+
237
+ print ("Array elements:" )
238
+ for elem in arr :
239
+ print (f"{ elem } " )
240
+
241
+ print ("\n Full array:" )
242
+ print (arr )
243
+
244
+ # Test different backends
245
+ print ("\n Testing backends in arrays:" )
246
+ arr_sleef = np .array ([3.14159265358979323846 ],dtype = QuadPrecDType (backend = 'sleef' ))
247
+ arr_longdouble = np .array ([3.14159265358979323846 ],dtype = QuadPrecDType (backend = 'longdouble' ))
248
+ print (f"Sleef array:{ arr_sleef } " )
249
+ print (f"Long double array:{ arr_longdouble } " )
250
+
251
+ def test_operations ():
252
+ print ("\n Testing basic operations:" )
253
+ a = QuadPrecision (3.14159265358979323846 )
254
+ b = QuadPrecision (2.71828182845904523536 )
255
+
256
+ print (f"a ={ a } " )
257
+ print (f"b ={ b } " )
258
+ print (f"a + b ={ a + b } " )
259
+ print (f"a - b ={ a - b } " )
260
+ print (f"a * b ={ a * b } " )
261
+ print (f"a / b ={ a / b } " )
262
+
263
+ def test ():
264
+ # Run tests for both backends
265
+ for backend in ['sleef' ,'longdouble' ]:
266
+ test_scalar_ops (backend )
267
+ test_casting (backend )
268
+ test_edge_cases (backend )
269
+ test_ufuncs (backend )
270
+ test_quad_precision ()
271
+ test_quad_dtype ()
272
+ test_operations ()
273
+ print ("*" * 50 )
274
+
275
+ print ("All tests completed successfully" )
276
+
277
+ def dot (a ,b ):
278
+ r = np .dot (a ,b )
279
+ return r
280
+
281
+ if __name__ == "__main__" :
282
+ a = np .array ([1 ,2 ,3 ],dtype = QuadPrecDType ())
283
+ print (dot (a ,a ))