Система. Математика. Круглая ошибка?

Я писал функцию для округления числа к двум местам. И я нашел ошибку, когда я пробовал к круглым определенным значениям. Так, я выполнил код:

class Program {
    static void Main(string[] args) {
        int limit = 100;

        for (int number = 0; number <= limit; number++) {
            Console.WriteLine((System.Math.Round((double)(number+0.995),2,MidpointRounding.AwayFromZero)));
        }
    }
}

И я нашел что: 8.99 9.99 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 32.99 33.99 34.99 35.99 36.99 37.99 38.99 39.99

числа не округлены к их следующему значению.

Когда я выполняю тот же код до 1500: Я получаю числа:

8.99 9.99 32.99 33.99 34.99 35.99 36.99 37.99 38.99 39.99 1024.99 1025.99 1026.99 1027.99 1028.99 1029.99 1030.99 1031.99 1032.99 1033.99 1034.99 1035.99 1036.99 1037.99 1038.99 1039.99 1040.99 1041.99 1042.99 1043.99 1044.99 1045.99 1046.99 1047.99 1048.99 1049.99 1050.99 1051.99 1052.99 1053.99 1054.99 1055.99 1056.99 1057.99 1058.99 1059.99 1060.99 1061.99 1062.99 1063.99 1064.99 1065.99 1066.99 1067.99 1068.99 1069.99 1070.99 1071.99 1072.99 1073.99 1074.99 1075.99 1076.99 1077.99 1078.99 1079.99 1080.99 1081.99 1082.99 1083.99 1084.99 1085.99 1086.99 1087.99 1088.99 1089.99 1090.99 1091.99 1092.99 1093.99 1094.99 1095.99 1096.99 1097.99 1098.99 1099.99 1100.99 1101.99 1102.99 1103.99 1104.99 1105.99 1106.99 1107.99 1108.99 1109.99 1110.99 1111.99 1112.99 1113.99 1114.99 1115.99 1116.99 1117.99 1118.99 1119.99 1120.99 1121.99 1122.99 1123.99 1124.99 1125.99 1126.99 1127.99 1128.99 1129.99 1130.99 1131.99 1132.99 1133.99 1134.99 1135.99 1136.99 1137.99 1138.99 1139.99 1140.99 1141.99 1142.99 1143.99 1144.99 1145.99 1146.99 1147.99 1148.99 1149.99 1150.99 1151.99 1152.99 1153.99 1154.99 1155.99 1156.99 1157.99 1158.99 1159.99 1160.99 1161.99 1162.99 1163.99 1164.99 1165.99 1166.99 1167.99 1168.99 1169.99 1170.99 1171.99 1172.99 1173.99 1174.99 1175.99 1176.99 1177.99 1178.99 1179.99 1180.99 1181.99 1182.99 1183.99 1184.99 1185.99 1186.99 1187.99 1188.99 1189.99 1190.99 1191.99 1192.99 1193.99 1194.99 1195.99 1196.99 1197.99 1198.99 1199.99 1200.99 1201.99 1202.99 1203.99 1204.99 1205.99 1206.99 1207.99 1208.99 1209.99 1210.99 1211.99 1212.99 1213.99 1214.99 1215.99 1216.99 1217.99 1218.99 1219.99 1220.99 1221.99 1222.99 1223.99 1224.99 1225.99 1226.99 1227.99 1228.99 1229.99 1230.99 1231.99 1232.99 1233.99 1234.99 1235.99 1236.99 1237.99 1238.99 1239.99 1240.99 1241.99 1242.99 1243.99 1244.99 1245.99 1246.99 1247.99 1248.99 1249.99 1250.99 1251.99 1252.99 1253.99 1254.99 1255.99 1256.99 1257.99 1258.99 1259.99 1260.99 1261.99 1262.99 1263.99 1264.99 1265.99 1266.99 1267.99 1268.99 1269.99 1270.99 1271.99 1272.99 1273.99 1274.99 1275.99 1276.99 1277.99 1278.99 1279.99 1280.99 1281.99 1282.99 1283.99 1284.99 1285.99 1286.99 1287.99 1288.99 1289.99 1290.99 1291.99 1292.99 1293.99 1294.99 1295.99 1296.99 1297.99 1298.99 1299.99 1300.99 1301.99 1302.99 1303.99 1304.99 1305.99 1306.99 1307.99 1308.99 1309.99

которые не округлены к следующему числу! Имеет любого любая идея о почему ее случай для этих определенных чисел!

7
задан abatishchev 18 June 2010 в 08:13
поделиться

1 ответ

Проблема в том, что когда вы берете значение «число + 0,995», оно не будет точно числом + 0,995 по обычным причинам, по которым двоичная с плавающей запятой не представляет точно десятичные значения.

Иногда это будет немного больше, а иногда будет немного меньше. Когда меньше , и вы округляете этот результат до двух десятичных знаков, вы получаете бит «0,99». Возможно, что Math.Round пытается в какой-то мере учесть это, но я не уверен в точных деталях.

Решение - там, где это возможно - использовать десятичное вместо double для вещей, где важны десятичные цифры .

См. Мои статьи о двоичном с плавающей запятой и десятичном с плавающей запятой в .NET для получения дополнительной информации.

Вот программа, использующая мой код DoubleConverter , которая показывает неточность после добавления 0,995:

using System;

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 100; i++)
        {
            double d = i + 0.995;
            Console.WriteLine(DoubleConverter.ToExactString(d));
        }
    }
}

Результаты:

0.99499999999999999555910790149937383830547332763671875 1.99500000000000010658141036401502788066864013671875 2,99500000000000010658141036401502788066864013671875 3.99500000000000010658141036401502788066864013671875 4.99500000000000010658141036401502788066864013671875 5.99500000000000010658141036401502788066864013671875 6.99500000000000010658141036401502788066864013671875 7.99500000000000010658141036401502788066864013671875 8.9949999999999992184029906638897955417633056640625 9.9949999999999992184029906638897955417633056640625 10.9949999999999992184029906638897955417633056640625 11.9949999999999992184029906638897955417633056640625 12.9949999999999992184029906638897955417633056640625 13.9949999999999992184029906638897955417633056640625 14.9949999999999992184029906638897955417633056640625 15.9949999999999992184029906638897955417633056640625 16.995000000000000994759830064140260219573974609375 17.995000000000000994759830064140260219573974609375 18.995000000000000994759830064140260219573974609375 19.995000000000000994759830064140260219573974609375 20.995000000000000994759830064140260219573974609375 ...

(Обратите внимание, что, хотя начинает с 0,994 на 8, он продолжается до 15 - тогда как Math.Round «исправляет» себя на 10.)

10
ответ дан 7 December 2019 в 01:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: