@@ -244,13 +244,91 @@ def type_info(np_type):
244244 # at float64 precision. The finfo values give nexp == 15 (as for intel
245245 # 80) but in calculations nexp in fact appears to be 11 as for float64
246246 ret .update (dict (width = width ))
247- elif vals == (1 , 1 , 16 ) and processor () == 'powerpc' : # broken PPC
248- ret .update (dict (nmant = 106 , width = width ))
247+ # Oh dear, we don't recognize the type information. Try some known types
248+ # and then give up. At this stage we're expecting exotic longdouble or their
249+ # complex equivalent.
250+ if not np_type in (np .longdouble , np .longcomplex ) or width not in (16 , 32 ):
251+ raise FloatingError ('We had not expected type %s' % np_type )
252+ if (vals == (1 , 1 , 16 ) and processor () == 'powerpc' and
253+ _check_maxexp (np .longdouble , 1024 )):
254+ # double pair on PPC. The _check_nmant routine does not work for this
255+ # type, hence the processor check
256+ ret .update (dict (nmant = 106 , width = width ))
257+ elif (_check_nmant (np .longdouble , 112 ) and
258+ _check_maxexp (np .longdouble , 16384 )):
259+ # binary 128, but with some busted type information. np.longcomplex
260+ # seems to break here too, so we need to use np.longdouble and
261+ # complexify
262+ two = np .longdouble (2 )
263+ # See: http://matthew-brett.github.com/pydagogue/floating_point.html
264+ max_val = (two ** 113 - 1 ) / (two ** 112 ) * two ** 16383
265+ if np_type is np .longcomplex :
266+ max_val += 0j
267+ ret = dict (min = - max_val ,
268+ max = max_val ,
269+ nmant = 112 ,
270+ nexp = 15 ,
271+ minexp = - 16382 ,
272+ maxexp = 16384 ,
273+ width = width )
249274 else : # don't recognize the type
250275 raise FloatingError ('We had not expected type %s' % np_type )
251276 return ret
252277
253278
279+ def _check_nmant (np_type , nmant ):
280+ """ True if fp type `np_type` seems to have `nmant` significand digits
281+
282+ Note 'digits' does not include implicit digits. And in fact if there are no
283+ implicit digits, the `nmant` number is one less than the actual digits.
284+ Assumes base 2 representation.
285+
286+ Parameters
287+ ----------
288+ np_type : numpy type specifier
289+ Any specifier for a numpy dtype
290+ nmant : int
291+ Number of digits to test against
292+
293+ Returns
294+ -------
295+ tf : bool
296+ True if `nmant` is the correct number of significand digits, false
297+ otherwise
298+ """
299+ np_type = np .dtype (np_type ).type
300+ max_contig = np_type (2 ** (nmant + 1 )) # maximum of contiguous integers
301+ tests = max_contig + np .array ([- 2 , - 1 , 0 , 1 , 2 ], dtype = np_type )
302+ return np .all (tests - max_contig == [- 2 , - 1 , 0 , 0 , 2 ])
303+
304+
305+ def _check_maxexp (np_type , maxexp ):
306+ """ True if fp type `np_type` seems to have `maxexp` maximum exponent
307+
308+ We're testing "maxexp" as returned by numpy. This value is set to one
309+ greater than the maximum power of 2 that `np_type` can represent.
310+
311+ Assumes base 2 representation. Very crude check
312+
313+ Parameters
314+ ----------
315+ np_type : numpy type specifier
316+ Any specifier for a numpy dtype
317+ maxexp : int
318+ Maximum exponent to test against
319+
320+ Returns
321+ -------
322+ tf : bool
323+ True if `maxexp` is the correct maximum exponent, False otherwise.
324+ """
325+ dt = np .dtype (np_type )
326+ np_type = dt .type
327+ two = np_type (2 ).reshape ((1 ,)) # to avoid upcasting
328+ return (np .isfinite (two ** (maxexp - 1 )) and
329+ not np .isfinite (two ** maxexp ))
330+
331+
254332def as_int (x , check = True ):
255333 """ Return python integer representation of number
256334
0 commit comments