@@ -747,6 +747,189 @@ def test_empty_bytes_raises_error(self):
747747 with pytest .raises (ValueError ):
748748 bytes_array .astype (QuadPrecDType ())
749749
750+
751+ class TestStringDTypeCasting :
752+ @pytest .mark .parametrize ("input_val" , [
753+ "3.141592653589793238462643383279502884197" ,
754+ "2.71828182845904523536028747135266249775" ,
755+ "1.0" ,
756+ "-1.0" ,
757+ "0.0" ,
758+ "-0.0" ,
759+ "1e100" ,
760+ "1e-100" ,
761+ "1.23456789012345678901234567890123456789" ,
762+ "-9.87654321098765432109876543210987654321" ,
763+ ])
764+ def test_stringdtype_to_quad_basic (self , input_val ):
765+ """Test basic StringDType to QuadPrecision conversion"""
766+ str_array = np .array ([input_val ], dtype = np .dtypes .StringDType ())
767+ quad_array = str_array .astype (QuadPrecDType ())
768+
769+ assert quad_array .dtype .name == "QuadPrecDType128"
770+ expected = np .array ([input_val ], dtype = QuadPrecDType ())
771+ np .testing .assert_array_equal (quad_array , expected )
772+
773+ @pytest .mark .parametrize ("input_val" , [
774+ "3.1415926535897932384626433832795028" , # pi to quad precision
775+ "2.7182818284590452353602874713526623" , # e to quad precision
776+ "1.0e+100" , # scientific notation (normalized form)
777+ "1.0e-100" , # scientific notation (normalized form)
778+ "0.0" ,
779+ "-0.0" ,
780+ "inf" ,
781+ "-inf" ,
782+ "nan" ,
783+ "1.0" ,
784+ "-1.0" ,
785+ "123.456" ,
786+ "-123.456" ,
787+ ])
788+ def test_stringdtype_roundtrip (self , input_val ):
789+ str_array = np .array ([input_val ], dtype = np .dtypes .StringDType ())
790+ quad_array = str_array .astype (QuadPrecDType ())
791+ result_str_array = quad_array .astype (np .dtypes .StringDType ())
792+
793+ np .testing .assert_array_equal (result_str_array , str_array )
794+
795+ @pytest .mark .parametrize ("original" , [
796+ QuadPrecision ("0.417022004702574000667425480060047" ),
797+ QuadPrecision ("1.23456789012345678901234567890123456789" ),
798+ pytest .param (numpy_quaddtype .pi , id = "pi" ),
799+ pytest .param (numpy_quaddtype .e , id = "e" ),
800+ QuadPrecision ("1e-100" ),
801+ QuadPrecision ("1e100" ),
802+ QuadPrecision ("-3.14159265358979323846264338327950288419" ),
803+ QuadPrecision ("0.0" ),
804+ QuadPrecision ("-0.0" ),
805+ QuadPrecision ("1.0" ),
806+ QuadPrecision ("-1.0" ),
807+ ])
808+ def test_quad_to_stringdtype_roundtrip (self , original ):
809+ """Test QuadPrecision -> StringDType -> QuadPrecision preserves value"""
810+ quad_array = np .array ([original ], dtype = QuadPrecDType ())
811+ str_array = quad_array .astype (np .dtypes .StringDType ())
812+ reconstructed = str_array .astype (QuadPrecDType ())
813+
814+ if np .isnan (original ):
815+ assert np .isnan (reconstructed [0 ])
816+ else :
817+ np .testing .assert_array_equal (reconstructed , quad_array )
818+
819+ # ============ Special Values Tests ============
820+
821+ @pytest .mark .parametrize ("input_str,check_func" , [
822+ ("inf" , lambda x : np .isinf (float (x )) and float (x ) > 0 ),
823+ ("-inf" , lambda x : np .isinf (float (x )) and float (x ) < 0 ),
824+ ("+inf" , lambda x : np .isinf (float (x )) and float (x ) > 0 ),
825+ ("Inf" , lambda x : np .isinf (float (x )) and float (x ) > 0 ),
826+ ("Infinity" , lambda x : np .isinf (float (x )) and float (x ) > 0 ),
827+ ("-Infinity" , lambda x : np .isinf (float (x )) and float (x ) < 0 ),
828+ ("INF" , lambda x : np .isinf (float (x )) and float (x ) > 0 ),
829+ ("INFINITY" , lambda x : np .isinf (float (x )) and float (x ) > 0 ),
830+ ])
831+ def test_stringdtype_infinity_variants (self , input_str , check_func ):
832+ """Test various infinity representations in StringDType"""
833+ str_array = np .array ([input_str ], dtype = np .dtypes .StringDType ())
834+ quad_array = str_array .astype (QuadPrecDType ())
835+
836+ assert check_func (quad_array [0 ]), f"Failed for { input_str } "
837+
838+ @pytest .mark .parametrize ("input_str" , [
839+ "nan" , "NaN" , "NAN" , "+nan" , "-nan" ,
840+ "nan()" , "nan(123)" , "NaN(payload)" ,
841+ ])
842+ def test_stringdtype_nan_variants (self , input_str ):
843+ """Test various NaN representations in StringDType"""
844+ str_array = np .array ([input_str ], dtype = np .dtypes .StringDType ())
845+ quad_array = str_array .astype (QuadPrecDType ())
846+
847+ assert np .isnan (float (quad_array [0 ])), f"Expected NaN for { input_str } "
848+
849+ def test_stringdtype_negative_zero (self ):
850+ neg_zero = QuadPrecision ("-0.0" )
851+ quad_array = np .array ([neg_zero ], dtype = QuadPrecDType ())
852+ assert np .signbit (quad_array [0 ]), "Input should have negative zero signbit"
853+ str_array = quad_array .astype (np .dtypes .StringDType ())
854+ assert str_array [0 ] == "-0.0" , f"Expected '-0.0', got '{ str_array [0 ]} '"
855+ roundtrip = str_array .astype (QuadPrecDType ())
856+ assert np .signbit (roundtrip [0 ]), "Signbit should be preserved after round-trip"
857+ assert float (roundtrip [0 ]) == 0.0 , "Value should be zero"
858+
859+ # ============ Whitespace Handling Tests ============
860+
861+ @pytest .mark .parametrize ("input_str,expected" , [
862+ (" 3.14" , "3.14" ),
863+ ("3.14 " , "3.14" ),
864+ (" 3.14 " , "3.14" ),
865+ ("\t 3.14\t " , "3.14" ),
866+ ("\n 3.14\n " , "3.14" ),
867+ (" \t \n 3.14 \t \n " , "3.14" ),
868+ ])
869+ def test_stringdtype_whitespace_handling (self , input_str , expected ):
870+ """Test that StringDType handles whitespace correctly"""
871+ str_array = np .array ([input_str ], dtype = np .dtypes .StringDType ())
872+ quad_array = str_array .astype (QuadPrecDType ())
873+ expected_quad = QuadPrecision (expected )
874+
875+ np .testing .assert_array_equal (quad_array , np .array ([expected_quad ], dtype = QuadPrecDType ()))
876+
877+ @pytest .mark .parametrize ("invalid_str" , [
878+ "" ,
879+ "not_a_number" ,
880+ "abc123" ,
881+ "1.23.45" ,
882+ "1e" ,
883+ "++1.0" ,
884+ "--1.0" ,
885+ "+-1.0" ,
886+ "1.0abc" ,
887+ "abc1.0" ,
888+ "3.14ñ" ,
889+ "π" ,
890+ ])
891+ def test_stringdtype_invalid_input (self , invalid_str ):
892+ """Test that invalid StringDType input raises ValueError"""
893+ str_array = np .array ([invalid_str ], dtype = np .dtypes .StringDType ())
894+
895+ with pytest .raises (ValueError ):
896+ str_array .astype (QuadPrecDType ())
897+
898+
899+ @pytest .mark .parametrize ("backend" , ["sleef" , "longdouble" ])
900+ @pytest .mark .parametrize ("input_str" , [
901+ "1.0" ,
902+ "-1.0" ,
903+ "3.141592653589793238462643383279502884197" ,
904+ "1e100" ,
905+ "1e-100" ,
906+ "0.0" ,
907+ ])
908+ def test_stringdtype_backend_consistency (self , backend , input_str ):
909+ """Test that StringDType parsing works consistently across backends"""
910+ str_array = np .array ([input_str ], dtype = np .dtypes .StringDType ())
911+ quad_array = str_array .astype (QuadPrecDType (backend = backend ))
912+ scalar_val = QuadPrecision (input_str , backend = backend )
913+ np .testing .assert_array_equal (quad_array , np .array ([scalar_val ], dtype = QuadPrecDType (backend = backend )))
914+
915+ def test_stringdtype_empty_array (self ):
916+ """Test conversion of empty StringDType array"""
917+ str_array = np .array ([], dtype = np .dtypes .StringDType ())
918+ quad_array = str_array .astype (QuadPrecDType ())
919+ np .testing .assert_array_equal (quad_array , np .array ([], dtype = QuadPrecDType ()))
920+
921+ @pytest .mark .parametrize ("size" , [500 , 1000 , 10000 ])
922+ def test_stringdtype_large_array (self , size ):
923+ """Test conversion of large StringDType array"""
924+ str_values = [str (i * 0.001 ) for i in range (size )]
925+ str_array = np .array (str_values , dtype = np .dtypes .StringDType ())
926+ quad_array = str_array .astype (QuadPrecDType ())
927+
928+ assert quad_array .shape == (size ,)
929+ np .testing .assert_array_equal (quad_array , np .array (str_values , dtype = QuadPrecDType ()))
930+
931+
932+
750933class TestStringParsingEdgeCases :
751934 """Test edge cases in NumPyOS_ascii_strtoq string parsing"""
752935 @pytest .mark .parametrize ("input_str" , ['3.14' , '-2.71' , '0.0' , '1e10' , '-1e-10' ])
0 commit comments