@@ -5451,86 +5451,74 @@ def test_same_value_cast_quad_to_int(self, dtype, passing, failing):
54515451 with pytest .raises (ValueError ):
54525452 q .astype (dtype , casting = "same_value" )
54535453
5454- # @pytest.mark.parametrize("dtype,passing,failing", [
5455- # # float16/half: 11-bit significand (10 explicit + 1 implicit)
5456- # # max: 65504, exact integers up to 2^11 = 2048
5457- # ("float16",
5458- # [0.0, -0.0, float('inf'), float('-inf'), float('nan'),
5459- # 1.0, -1.0, 0.5, 0.25,
5460- # 2048.0, # 2^11, largest consecutive integer
5461- # 65504.0, # max representable
5462- # 2**-14, # min positive normal
5463- # ],
5464- # [65536.0, # overflow (> max)
5465- # # precision loss (first non-representable int > 2048)
5466- # 2049.0,
5467- # 1.0 + 2**-11, # precision loss (step from 1.0 is 2^-10)
5468- # ]),
5469-
5470- # ("half", # alias, same values
5471- # [0.0, float('inf'), float('-inf'), float('nan'), 1.0, 2048.0],
5472- # [65536.0, 2049.0]),
5473-
5474- # # float32: 24-bit significand (23 explicit + 1 implicit)
5475- # # max: ~3.4e38, exact integers up to 2^24 = 16777216
5476- # ("float32",
5477- # [0.0, -0.0, float('inf'), float('-inf'), float('nan'),
5478- # 1.0, -1.0, 0.5, 0.25,
5479- # 16777216.0, # 2^24, largest consecutive integer
5480- # 3.4028235e38, # max representable (approx)
5481- # 2**-126, # min positive normal
5482- # ],
5483- # [16777217.0, # precision loss (first non-representable int)
5484- # 1e39, # overflow
5485- # 1.0 + 2**-24, # precision loss (step from 1.0 is 2^-23)
5486- # ]),
5487-
5488- # ("float", # alias
5489- # [0.0, float('inf'), float('-inf'), float('nan'), 1.0, 16777216.0],
5490- # [16777217.0, 1e39]),
5491-
5492- # # float64: 53-bit significand (52 explicit + 1 implicit)
5493- # # max: ~1.8e308, exact integers up to 2^53
5494- # ("float64",
5495- # [0.0, -0.0, float('inf'), float('-inf'), float('nan'),
5496- # 1.0, -1.0, 0.5, 0.25,
5497- # 2.0**53, # largest consecutive integer
5498- # 1.7976931348623157e308, # max representable (approx)
5499- # 2**-1022, # min positive normal
5500- # ],
5501- # [2.0**53 + 1, # precision loss
5502- # 1e309, # overflow
5503- # 1.0 + 2**-53, # precision loss (step from 1.0 is 2^-52)
5504- # ]),
5505-
5506- # ("double", # alias
5507- # [0.0, float('inf'), float('-inf'), float('nan'), 1.0, 2.0**53],
5508- # [2.0**53 + 1, 1e309]),
5509-
5510- # # longdouble: platform-dependent!
5511- # # x86 Linux: 80-bit extended, 64-bit significand → integers up to 2^64
5512- # # Windows/macOS: often same as float64
5513- # # Consider using np.finfo(np.longdouble).nmant to adjust dynamically
5514- # # ("longdouble",
5515- # # [0.0, -0.0, float('inf'), float('-inf'), float('nan'),
5516- # # 1.0, 2.0**53, 2.0**53 + 1], # 2^53+1 passes if longdouble > float64
5517- # # # Failing cases depend on platform - maybe skip or parametrize separately
5518- # # []),
5519- # ])
5520- # def test_same_value_cast_floats(self, dtype, passing, failing):
5521- # for val in passing:
5522- # q = np.array([val], dtype=QuadPrecDType())
5523- # result = q.astype(dtype, casting="same_value")
5524- # # Use appropriate comparison for nan
5525- # if np.isnan(val):
5526- # assert np.isnan(result)
5527- # else:
5528- # assert result == val
5529-
5530- # for val in failing:
5531- # q = np.array([val], dtype=QuadPrecDType())
5532- # with pytest.raises(ValueError):
5533- # q.astype(dtype, casting="same_value")
5454+ @pytest .mark .parametrize ("dtype" , [
5455+ np .float16 , np .float32 , np .float64 , np .longdouble
5456+ ])
5457+ def test_same_value_cast_floats_special_values (self , dtype ):
5458+ """Test that special floating-point values roundtrip correctly."""
5459+ special_values = [0.0 , - 0.0 , float ('inf' ), float ('-inf' ), float ('nan' )]
5460+
5461+ for val in special_values :
5462+ q = np .array ([val ], dtype = QuadPrecDType ())
5463+ result = q .astype (dtype , casting = "same_value" )
5464+ if np .isnan (val ):
5465+ assert np .isnan (result ), f"NaN failed for { dtype } "
5466+ else :
5467+ assert result == val , f"{ val } failed for { dtype } "
5468+
5469+ @pytest .mark .parametrize ("dtype" , [
5470+ np .float16 , np .float32 , np .float64 , np .longdouble
5471+ ])
5472+ def test_same_value_cast_floats_within_range (self , dtype ):
5473+ """Test values that should roundtrip exactly within dtype's precision."""
5474+ info = np .finfo (dtype )
5475+
5476+ # Values that should pass (exactly representable)
5477+ passing_values = [
5478+ 1.0 , - 1.0 , 0.5 , - 0.5 , 0.25 , - 0.25 ,
5479+ 2.0 , 4.0 , 8.0 , # powers of 2
5480+ info .tiny , # min positive normal
5481+ 2 ** info .nmant , # largest consecutive integer
5482+ ]
5483+
5484+ for val in passing_values :
5485+ # Ensure the value is representable in the target dtype first
5486+ target_val = dtype (val )
5487+ q = np .array ([target_val ], dtype = QuadPrecDType ())
5488+ result = q .astype (dtype , casting = "same_value" )
5489+ assert result == target_val , f"Value { val } failed for { dtype } "
5490+
5491+
5492+ @pytest .mark .parametrize ("dtype" , [
5493+ np .float16 , np .float32 , np .float64 , np .longdouble
5494+ ])
5495+ def test_same_value_cast_floats_precision_loss (self , dtype ):
5496+ """Test values that cannot be represented exactly and should fail."""
5497+ from decimal import Decimal , getcontext
5498+
5499+ getcontext ().prec = 50 # plenty for quad precision
5500+ info = np .finfo (dtype )
5501+ nmant = info .nmant # 10 for f16, 23 for f32, 52 for f64
5502+
5503+ # First odd integer beyond exact representability
5504+ first_bad_int = 2 ** (nmant + 1 ) + 1
5505+ # Value between 1.0 and 1.0 + eps (i.e., 1 + eps/2)
5506+ # eps = 2^-nmant, so eps/2 = 2^-(nmant+1)
5507+ one_plus_half_eps = Decimal (1 ) + Decimal (2 ) ** - (nmant + 1 )
5508+
5509+ # Value between 2.0 and 2.0 + 2*eps
5510+ two_plus_eps = Decimal (2 ) + Decimal (2 ) ** - nmant
5511+
5512+ failing_values = [
5513+ str (first_bad_int ),
5514+ str (one_plus_half_eps ),
5515+ str (two_plus_eps ),
5516+ ]
5517+
5518+ for val in failing_values :
5519+ q = np .array ([val ], dtype = QuadPrecDType ())
5520+ with pytest .raises (ValueError ):
5521+ q .astype (dtype , casting = "same_value" )
55345522
55355523 # @pytest.mark.parametrize("dtype", [
55365524 # "S50", "U50", "<U50", ">U50", "S100", "U100", "<U100", ">U100", np.dtypes.StringDType()])
0 commit comments