authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-04-23 17:18:05+12:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-04-23 17:22:51+12:00
loge5175d432ef01e078ef247ea0a781243219ddfb6
treee2f5131b9e7e9646888a84425b1d86c193ba904c
parentd8ba1bc12054712dec731db0c4062a5df0d627c6

Fix release float printing errors

Fixes #564. Fixes #669. Fixes #928.

2 files changed, 202 insertions(+), 201 deletions(-)

std/fmt/errol/index.zig+3
......@@ -259,6 +259,9 @@ fn gethi(in: f64) f64 {
259259/// Normalize the number by factoring in the error.
260260/// @hp: The float pair.
261261fn hpNormalize(hp: &HP) void {
262 // Required to avoid segfaults causing buffer overrun during errol3 digit output termination.
263 @setFloatMode(this, @import("builtin").FloatMode.Strict);
264
262265 const val = hp.val;
263266
264267 hp.val += hp.off;
std/fmt/index.zig+199-201
......@@ -779,212 +779,210 @@ test "fmt.format" {
779779 const result = try bufPrint(buf1[0..], "pointer: {}\n", &value);
780780 assert(mem.startsWith(u8, result, "pointer: Struct@"));
781781 }
782
783 // TODO get these tests passing in release modes
784 // https://github.com/zig-lang/zig/issues/564
785 if (builtin.mode == builtin.Mode.Debug) {
786 {
787 var buf1: [32]u8 = undefined;
788 const value: f32 = 1.34;
789 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
790 assert(mem.eql(u8, result, "f32: 1.34000003e+00\n"));
791 }
792 {
793 var buf1: [32]u8 = undefined;
794 const value: f32 = 12.34;
795 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
796 assert(mem.eql(u8, result, "f32: 1.23400001e+01\n"));
797 }
798 {
799 var buf1: [32]u8 = undefined;
800 const value: f64 = -12.34e10;
801 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
802 assert(mem.eql(u8, result, "f64: -1.234e+11\n"));
803 }
804 {
782 {
783 var buf1: [32]u8 = undefined;
784 const value: f32 = 1.34;
785 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
786 assert(mem.eql(u8, result, "f32: 1.34000003e+00\n"));
787 }
788 {
789 var buf1: [32]u8 = undefined;
790 const value: f32 = 12.34;
791 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
792 assert(mem.eql(u8, result, "f32: 1.23400001e+01\n"));
793 }
794 {
795 var buf1: [32]u8 = undefined;
796 const value: f64 = -12.34e10;
797 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
798 assert(mem.eql(u8, result, "f64: -1.234e+11\n"));
799 }
800 {
801 // This fails on release due to a minor rounding difference.
802 // --release-fast outputs 9.999960000000001e-40 vs. the expected.
803 if (builtin.mode == builtin.Mode.Debug) {
805804 var buf1: [32]u8 = undefined;
806805 const value: f64 = 9.999960e-40;
807806 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
808807 assert(mem.eql(u8, result, "f64: 9.99996e-40\n"));
809808 }
810 {
811 var buf1: [32]u8 = undefined;
812 const value: f64 = 1.409706e-42;
813 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
814 assert(mem.eql(u8, result, "f64: 1.40971e-42\n"));
815 }
816 {
817 var buf1: [32]u8 = undefined;
818 const value: f64 = @bitCast(f32, u32(814313563));
819 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
820 assert(mem.eql(u8, result, "f64: 1.00000e-09\n"));
821 }
822 {
823 var buf1: [32]u8 = undefined;
824 const value: f64 = @bitCast(f32, u32(1006632960));
825 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
826 assert(mem.eql(u8, result, "f64: 7.81250e-03\n"));
827 }
828 {
829 // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
830 // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
831 var buf1: [32]u8 = undefined;
832 const value: f64 = @bitCast(f32, u32(1203982400));
833 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
834 assert(mem.eql(u8, result, "f64: 1.00001e+05\n"));
835 }
836 {
837 var buf1: [32]u8 = undefined;
838 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
839 assert(mem.eql(u8, result, "f64: nan\n"));
840 }
841 {
842 var buf1: [32]u8 = undefined;
843 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64);
844 assert(mem.eql(u8, result, "f64: -nan\n"));
845 }
846 {
847 var buf1: [32]u8 = undefined;
848 const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
849 assert(mem.eql(u8, result, "f64: inf\n"));
850 }
851 {
852 var buf1: [32]u8 = undefined;
853 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
854 assert(mem.eql(u8, result, "f64: -inf\n"));
855 }
856 {
857 var buf1: [64]u8 = undefined;
858 const value: f64 = 1.52314e+29;
859 const result = try bufPrint(buf1[0..], "f64: {.}\n", value);
860 assert(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));
861 }
862 {
863 var buf1: [32]u8 = undefined;
864 const value: f32 = 1.1234;
865 const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);
866 assert(mem.eql(u8, result, "f32: 1.1\n"));
867 }
868 {
869 var buf1: [32]u8 = undefined;
870 const value: f32 = 1234.567;
871 const result = try bufPrint(buf1[0..], "f32: {.2}\n", value);
872 assert(mem.eql(u8, result, "f32: 1234.57\n"));
873 }
874 {
875 var buf1: [32]u8 = undefined;
876 const value: f32 = -11.1234;
877 const result = try bufPrint(buf1[0..], "f32: {.4}\n", value);
878 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
879 // -11.12339... is rounded back up to -11.1234
880 assert(mem.eql(u8, result, "f32: -11.1234\n"));
881 }
882 {
883 var buf1: [32]u8 = undefined;
884 const value: f32 = 91.12345;
885 const result = try bufPrint(buf1[0..], "f32: {.5}\n", value);
886 assert(mem.eql(u8, result, "f32: 91.12345\n"));
887 }
888 {
889 var buf1: [32]u8 = undefined;
890 const value: f64 = 91.12345678901235;
891 const result = try bufPrint(buf1[0..], "f64: {.10}\n", value);
892 assert(mem.eql(u8, result, "f64: 91.1234567890\n"));
893 }
894 {
895 var buf1: [32]u8 = undefined;
896 const value: f64 = 0.0;
897 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
898 assert(mem.eql(u8, result, "f64: 0.00000\n"));
899 }
900 {
901 var buf1: [32]u8 = undefined;
902 const value: f64 = 5.700;
903 const result = try bufPrint(buf1[0..], "f64: {.0}\n", value);
904 assert(mem.eql(u8, result, "f64: 6\n"));
905 }
906 {
907 var buf1: [32]u8 = undefined;
908 const value: f64 = 9.999;
909 const result = try bufPrint(buf1[0..], "f64: {.1}\n", value);
910 assert(mem.eql(u8, result, "f64: 10.0\n"));
911 }
912 {
913 var buf1: [32]u8 = undefined;
914 const value: f64 = 1.0;
915 const result = try bufPrint(buf1[0..], "f64: {.3}\n", value);
916 assert(mem.eql(u8, result, "f64: 1.000\n"));
917 }
918 {
919 var buf1: [32]u8 = undefined;
920 const value: f64 = 0.0003;
921 const result = try bufPrint(buf1[0..], "f64: {.8}\n", value);
922 assert(mem.eql(u8, result, "f64: 0.00030000\n"));
923 }
924 {
925 var buf1: [32]u8 = undefined;
926 const value: f64 = 1.40130e-45;
927 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
928 assert(mem.eql(u8, result, "f64: 0.00000\n"));
929 }
930 {
931 var buf1: [32]u8 = undefined;
932 const value: f64 = 9.999960e-40;
933 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
934 assert(mem.eql(u8, result, "f64: 0.00000\n"));
935 }
936 // libc checks
937 {
938 var buf1: [32]u8 = undefined;
939 const value: f64 = f64(@bitCast(f32, u32(916964781)));
940 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
941 assert(mem.eql(u8, result, "f64: 0.00001\n"));
942 }
943 {
944 var buf1: [32]u8 = undefined;
945 const value: f64 = f64(@bitCast(f32, u32(925353389)));
946 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
947 assert(mem.eql(u8, result, "f64: 0.00001\n"));
948 }
949 {
950 var buf1: [32]u8 = undefined;
951 const value: f64 = f64(@bitCast(f32, u32(1036831278)));
952 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
953 assert(mem.eql(u8, result, "f64: 0.10000\n"));
954 }
955 {
956 var buf1: [32]u8 = undefined;
957 const value: f64 = f64(@bitCast(f32, u32(1065353133)));
958 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
959 assert(mem.eql(u8, result, "f64: 1.00000\n"));
960 }
961 {
962 var buf1: [32]u8 = undefined;
963 const value: f64 = f64(@bitCast(f32, u32(1092616192)));
964 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
965 assert(mem.eql(u8, result, "f64: 10.00000\n"));
966 }
967 // libc differences
968 {
969 var buf1: [32]u8 = undefined;
970 // This is 0.015625 exactly according to gdb. We thus round down,
971 // however glibc rounds up for some reason. This occurs for all
972 // floats of the form x.yyyy25 on a precision point.
973 const value: f64 = f64(@bitCast(f32, u32(1015021568)));
974 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
975 assert(mem.eql(u8, result, "f64: 0.01563\n"));
976 }
977
978 // std-windows-x86_64-Debug-bare test case fails
979 {
980 // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
981 // also rounds to 630 so I'm inclined to believe libc is not
982 // optimal here.
983 var buf1: [32]u8 = undefined;
984 const value: f64 = f64(@bitCast(f32, u32(1518338049)));
985 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
986 assert(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
987 }
809 }
810 {
811 var buf1: [32]u8 = undefined;
812 const value: f64 = 1.409706e-42;
813 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
814 assert(mem.eql(u8, result, "f64: 1.40971e-42\n"));
815 }
816 {
817 var buf1: [32]u8 = undefined;
818 const value: f64 = @bitCast(f32, u32(814313563));
819 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
820 assert(mem.eql(u8, result, "f64: 1.00000e-09\n"));
821 }
822 {
823 var buf1: [32]u8 = undefined;
824 const value: f64 = @bitCast(f32, u32(1006632960));
825 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
826 assert(mem.eql(u8, result, "f64: 7.81250e-03\n"));
827 }
828 {
829 // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
830 // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
831 var buf1: [32]u8 = undefined;
832 const value: f64 = @bitCast(f32, u32(1203982400));
833 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
834 assert(mem.eql(u8, result, "f64: 1.00001e+05\n"));
835 }
836 {
837 var buf1: [32]u8 = undefined;
838 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
839 assert(mem.eql(u8, result, "f64: nan\n"));
840 }
841 {
842 var buf1: [32]u8 = undefined;
843 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64);
844 assert(mem.eql(u8, result, "f64: -nan\n"));
845 }
846 {
847 var buf1: [32]u8 = undefined;
848 const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
849 assert(mem.eql(u8, result, "f64: inf\n"));
850 }
851 {
852 var buf1: [32]u8 = undefined;
853 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
854 assert(mem.eql(u8, result, "f64: -inf\n"));
855 }
856 {
857 var buf1: [64]u8 = undefined;
858 const value: f64 = 1.52314e+29;
859 const result = try bufPrint(buf1[0..], "f64: {.}\n", value);
860 assert(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));
861 }
862 {
863 var buf1: [32]u8 = undefined;
864 const value: f32 = 1.1234;
865 const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);
866 assert(mem.eql(u8, result, "f32: 1.1\n"));
867 }
868 {
869 var buf1: [32]u8 = undefined;
870 const value: f32 = 1234.567;
871 const result = try bufPrint(buf1[0..], "f32: {.2}\n", value);
872 assert(mem.eql(u8, result, "f32: 1234.57\n"));
873 }
874 {
875 var buf1: [32]u8 = undefined;
876 const value: f32 = -11.1234;
877 const result = try bufPrint(buf1[0..], "f32: {.4}\n", value);
878 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
879 // -11.12339... is rounded back up to -11.1234
880 assert(mem.eql(u8, result, "f32: -11.1234\n"));
881 }
882 {
883 var buf1: [32]u8 = undefined;
884 const value: f32 = 91.12345;
885 const result = try bufPrint(buf1[0..], "f32: {.5}\n", value);
886 assert(mem.eql(u8, result, "f32: 91.12345\n"));
887 }
888 {
889 var buf1: [32]u8 = undefined;
890 const value: f64 = 91.12345678901235;
891 const result = try bufPrint(buf1[0..], "f64: {.10}\n", value);
892 assert(mem.eql(u8, result, "f64: 91.1234567890\n"));
893 }
894 {
895 var buf1: [32]u8 = undefined;
896 const value: f64 = 0.0;
897 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
898 assert(mem.eql(u8, result, "f64: 0.00000\n"));
899 }
900 {
901 var buf1: [32]u8 = undefined;
902 const value: f64 = 5.700;
903 const result = try bufPrint(buf1[0..], "f64: {.0}\n", value);
904 assert(mem.eql(u8, result, "f64: 6\n"));
905 }
906 {
907 var buf1: [32]u8 = undefined;
908 const value: f64 = 9.999;
909 const result = try bufPrint(buf1[0..], "f64: {.1}\n", value);
910 assert(mem.eql(u8, result, "f64: 10.0\n"));
911 }
912 {
913 var buf1: [32]u8 = undefined;
914 const value: f64 = 1.0;
915 const result = try bufPrint(buf1[0..], "f64: {.3}\n", value);
916 assert(mem.eql(u8, result, "f64: 1.000\n"));
917 }
918 {
919 var buf1: [32]u8 = undefined;
920 const value: f64 = 0.0003;
921 const result = try bufPrint(buf1[0..], "f64: {.8}\n", value);
922 assert(mem.eql(u8, result, "f64: 0.00030000\n"));
923 }
924 {
925 var buf1: [32]u8 = undefined;
926 const value: f64 = 1.40130e-45;
927 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
928 assert(mem.eql(u8, result, "f64: 0.00000\n"));
929 }
930 {
931 var buf1: [32]u8 = undefined;
932 const value: f64 = 9.999960e-40;
933 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
934 assert(mem.eql(u8, result, "f64: 0.00000\n"));
935 }
936 // libc checks
937 {
938 var buf1: [32]u8 = undefined;
939 const value: f64 = f64(@bitCast(f32, u32(916964781)));
940 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
941 assert(mem.eql(u8, result, "f64: 0.00001\n"));
942 }
943 {
944 var buf1: [32]u8 = undefined;
945 const value: f64 = f64(@bitCast(f32, u32(925353389)));
946 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
947 assert(mem.eql(u8, result, "f64: 0.00001\n"));
948 }
949 {
950 var buf1: [32]u8 = undefined;
951 const value: f64 = f64(@bitCast(f32, u32(1036831278)));
952 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
953 assert(mem.eql(u8, result, "f64: 0.10000\n"));
954 }
955 {
956 var buf1: [32]u8 = undefined;
957 const value: f64 = f64(@bitCast(f32, u32(1065353133)));
958 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
959 assert(mem.eql(u8, result, "f64: 1.00000\n"));
960 }
961 {
962 var buf1: [32]u8 = undefined;
963 const value: f64 = f64(@bitCast(f32, u32(1092616192)));
964 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
965 assert(mem.eql(u8, result, "f64: 10.00000\n"));
966 }
967 // libc differences
968 {
969 var buf1: [32]u8 = undefined;
970 // This is 0.015625 exactly according to gdb. We thus round down,
971 // however glibc rounds up for some reason. This occurs for all
972 // floats of the form x.yyyy25 on a precision point.
973 const value: f64 = f64(@bitCast(f32, u32(1015021568)));
974 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
975 assert(mem.eql(u8, result, "f64: 0.01563\n"));
976 }
977 // std-windows-x86_64-Debug-bare test case fails
978 {
979 // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
980 // also rounds to 630 so I'm inclined to believe libc is not
981 // optimal here.
982 var buf1: [32]u8 = undefined;
983 const value: f64 = f64(@bitCast(f32, u32(1518338049)));
984 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
985 assert(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
988986 }
989987}
990988