var funcs = [];
for (var i = 0; i < 3; i++) { // let's create 3 functions
funcs[i] = function(param) { // and store them in funcs
console.log("My value: " + param); // each should log its value.
};
}
for (var j = 0; j < 3; j++) {
funcs[j](j); // and now let's run each one to see with j
}
Во-первых, это не будет ошибкой C # в любом случае - это будет ошибка .NET. C # - это язык - он не решает, как реализован Math.Round
.
И, во-вторых, no - если вы читаете документы , вы увидите, что округление по умолчанию (округление до округления):
Возвращаемое значениеType: System.DoubleThe целое число, ближайшее a. Если дробная составляющая a находится на полпути между двумя целыми числами, одна из которых четная, а другая нечетная, то четное число возвращается. Обратите внимание, что этот метод возвращает
Double
вместо целочисленного типа.Замечания. Поведение этого метода следует за стандартом IEEE 754, раздел 4. Этот вид округления иногда называется округлением до ближайшего или округления банкира.
blockquote>Вы можете указать, как
Math.Round
должен округлить средние точки, используя перегрузку , чтобы избежать ошибки округления, которая возникает из-за постоянного округления среднего значения в одном направлении. который принимает значениеMidpointRounding
. Существует одна перегрузка сMidpointRounding
, соответствующей каждой из перегрузок, которая не имеет одного:
Round(Decimal)
/Round(Decimal, MidpointRounding)
Round(Double)
]Round(Decimal, Int32, MidpointRounding)
Round(Double, Int32)
/Round(Double, Int32, MidpointRounding)
Выполняется ли это по умолчанию был хорошо выбран или нет, это другое дело. (
MidpointRounding
был введен только в .NET 2.0. До этого я не уверен, что есть простой способ реализовать желаемое поведение, не делая этого самостоятельно.) В частности, история показала, что это не ожидаемый / g12] - и в большинстве случаев это кардинальный грех в дизайне API. Я вижу , почему Rounding Banker полезен ... но это все еще сюрприз для многих.Вам может быть интересно взглянуть на ближайшее эквивалентное перечисление Java ( ]
RoundingMode
), который предлагает еще больше возможностей. (Это касается не только средних точек.)
с использованием пользовательского округления
public int Round(double value)
{
double decimalpoints = Math.Abs(value - Math.Floor(value));
if (decimalpoints > 0.5)
return (int)Math.Round(value);
else
return (int)Math.Floor(value);
}
Из MSDN, Math.Round (double a) возвращается:
Целое число, ближайшее a. Если дробная составляющая a находится на полпути между двумя целыми числами, одна из которых четная, а другая нечетная, то возвращается четное число.
blockquote>... и поэтому 2.5, находясь на полпути между 2 и 3, округляется до четного числа (2). это называется округлением Banker (или округлым до четности) и является обычно используемым стандартом округления.
То же самое в статье MSDN:
] Поведение этого метода следует за стандартом IEEE 754, раздел 4. Этот вид округления иногда называется округлением до ближайшего или округления банкира. Это минимизирует ошибки округления, которые возникают из-за постоянного округления среднего значения в одном направлении.
blockquote>Вы можете указать другое поведение округления, вызвав перегрузки Math.Round, которые принимают режим
MidpointRounding
.
По умолчанию MidpointRounding.ToEven
, или округление банкиров ( 2.5 становится 2, 4.5 становится 4 и т. д. ) раньше меня поразило, записывая отчеты для учета, поэтому я напишу несколько слов о том, что я узнал, ранее и от изучения этого сообщения.
Из wikipedia
Происхождение термина округления банкиров остается более неясным. Если этот метод округления всегда был стандартом в банковской деятельности, доказательства оказались чрезвычайно трудными для поиска. Напротив, раздел 2 доклада Европейской комиссии «Введение евро и округление валютных сумм» предполагает, что ранее не было стандартного подхода к округлению банковского дела; и он указывает, что суммы «на полпути» должны быть округлены.
blockquote>Кажется, очень странный способ округления, особенно для банковских операций, если, конечно, банки не используют для приема большого количества депозитов даже суммы. Депозит £ 2,4 млн, но мы назовем его 2 млн фунтов стерлингов.
Стандарт IEEE 754 относится к 1985 году и дает оба способа округления, но с рекомендациями по стандарту банкира. Эта статья wikipedia имеет длинный список того, как языки реализуют округление (исправьте меня, если какое-либо из ниже сказанное неверно), и большинство из них не используют банкиров, но округление, которое вы преподаете в школе:
- C / C ++ round () из math.h раундов от нуля (не округление банкира)
- Java Math.Round округляется от нуля ( он наносит результат, добавляет 0.5, отбрасывает целое число). Есть альтернатива в BigDecimal
- Perl использует аналогичный путь к C
- Javascript такой же, как Java Math.Round.
Из MSDN:
По умолчанию Math.Round использует MidpointRounding.ToEven. Большинство людей не знакомы с «округлением до единого», поскольку альтернатива, «округление от нуля», чаще всего преподается в школе. .NET по умолчанию имеет значение «округление до четного», поскольку оно статистически превосходит, поскольку оно не разделяет тенденцию «округления от нуля» к округлению немного чаще, чем округляет его (при условии, что округленные числа имеют тенденцию быть положительными. )
blockquote>http://msdn.microsoft.com/en-us/library/system.math.round.aspx
Вот как я должен был работать над этим:
Public Function Round(number As Double, dec As Integer) As Double
Dim decimalPowerOfTen = Math.Pow(10, dec)
If CInt(number * decimalPowerOfTen) = Math.Round(number * decimalPowerOfTen, 2) Then
Return Math.Round(number, 2, MidpointRounding.AwayFromZero)
Else
Return CInt(number * decimalPowerOfTen + 0.5) / 100
End If
End Function
Попытка с 1.905 с двумя десятичными знаками даст 1.91, как ожидалось, но Math.Round(1.905,2,MidpointRounding.AwayFromZero)
дает 1.90! Метод Math.Round абсолютно несогласован и непригоден для большинства проблем, с которыми могут столкнуться программисты. Я должен проверить, вызвано ли (int) 1.905 * decimalPowerOfTen = Math.Round(number * decimalPowerOfTen, 2)
тем, что я не хочу округлять то, что должно быть округлено вниз.
Вы должны проверить MSDN для Math.Round
:
Поведение этого метода следует за стандартом IEEE 754, раздел 4. Этот вид округления иногда называют округлением до ближайшего или округления банкира.
blockquote>Вы можете указать поведение
Math.Round
с помощью перегрузки:Math.Round(2.5, 0, MidpointRounding.AwayFromZero); // gives 3 Math.Round(2.5, 0, MidpointRounding.ToEven); // gives 2
Это уродливо, как и все ад, но всегда производит правильное арифметическое округление.
public double ArithRound(double number,int places){
string numberFormat = "###.";
numberFormat = numberFormat.PadRight(numberFormat.Length + places, '#');
return double.Parse(number.ToString(numberFormat));
}
Silverlight не поддерживает параметр MidpointRounding. Ниже приведен метод расширения для Silverlight, который добавляет перечисление MidpointRounding:
public enum MidpointRounding
{
ToEven,
AwayFromZero
}
public static class DecimalExtensions
{
public static decimal Round(this decimal d, MidpointRounding mode)
{
return d.Round(0, mode);
}
/// <summary>
/// Rounds using arithmetic (5 rounds up) symmetrical (up is away from zero) rounding
/// </summary>
/// <param name="d">A Decimal number to be rounded.</param>
/// <param name="decimals">The number of significant fractional digits (precision) in the return value.</param>
/// <returns>The number nearest d with precision equal to decimals. If d is halfway between two numbers, then the nearest whole number away from zero is returned.</returns>
public static decimal Round(this decimal d, int decimals, MidpointRounding mode)
{
if ( mode == MidpointRounding.ToEven )
{
return decimal.Round(d, decimals);
}
else
{
decimal factor = Convert.ToDecimal(Math.Pow(10, decimals));
int sign = Math.Sign(d);
return Decimal.Truncate(d * factor + 0.5m * sign) / factor;
}
}
}
Источник: http://anderly.com/2009/08/08/silverlight-midpoint-rounding-solution/
Поскольку Silverlight не поддерживает параметр MidpointRounding, вы должны написать свой собственный. Что-то вроде:
public double RoundCorrect(double d, int decimals)
{
double multiplier = Math.Pow(10, decimals);
if (d < 0)
multiplier *= -1;
return Math.Floor((d * multiplier) + 0.5) / multiplier;
}
Для примеров, в том числе о том, как использовать это как расширение, см. Сообщение: Окно .NET и Silverlight
Простой способ:
Math.Ceiling(decimal.Parse(yourNumber + ""));
Рассмотрим задачу округления числа, содержащего долю, например, целого числа. Процесс округления в этом случае состоит в том, чтобы определить, какое целое число наилучшим образом представляет число, которое вы округливаете.
В общем или «арифметическом» округлении ясно, что 2.1, 2.2, 2.3 и 2.4 раунд 2,0; и 2,6, 2,7, 2,8 и 2,9 - 3,0.
Это оставляет 2,5, что не ближе к 2,0, чем к 3,0. Это зависит от вас, чтобы выбрать между 2.0 и 3.0, либо будет одинаково справедливым.
За минусом цифры -2,1, -2,2, -2,3 и -2,4 составят -2,0; и -2,6, 2,7, 2,8 и 2,9 составляли -3,0 при арифметическом округлении.
Для -2.5 необходим выбор между -2.0 и -3.0.
Другие формы округления
«Округление» принимает любое число с десятичными знаками и делает его следующим «целым» числом. Таким образом, не только 2.5 и 2.6 округляются до 3.0, но также делают 2.1 и 2.2.
Округление перемещает как положительные, так и отрицательные числа от нуля. Например. От 2,5 до 3,0 и от -2,5 до -3,0.
«Округление» сокращает число, сокращая ненужные цифры. Это приводит к перемещению чисел к нулю. Например. От 2,5 до 2,0 и от -2,5 до -2,0
В «округлении банкира» - в его наиболее распространенной форме - округленный округляемый округлый округлый округляющий округлый округлый округляющий округлый округлый округлый округляющий округлый округлый или округлый конец, так что результат округления всегда четное число. Таким образом, 2,5 раунда до 2,0, от 3,5 до 4,0, от 4,5 до 4,0, от 5,5 до 6,0 и т. Д.
«Альтернативное округление» изменяет процесс для любого .5 между округлением и округлением.
«Случайное округление» округляет a .5 вверх или вниз на совершенно случайной основе.
Симметрия и асимметрия
Функция округления называется «симметричной», если она либо округляет все числа от нуля или округляет все числа к нулю.
Функция является «асимметричной», если округляет положительные числа к нулю и отрицательные числа от нуля. 2,5-2,0; и -2,5 - -3,0.
Также асимметрична функция, которая округляет положительные числа от нуля и отрицательных чисел к нулю. Например. От 2,5 до 3,0; и -2,5 до -2,0.
Большинство людей думают о симметричном округлении, где -2,5 будут округлены до -3,0, а 3.5 будут округлены до 4.0. (в C # Round(AwayFromZero)
)
Это называется округлением до четного (или округления банкира), что является действительной стратегией округления для минимизации начисленных ошибок в суммах (MidpointRounding.ToEven)
. Теория состоит в том, что если вы всегда будете округлять 0,5 числа в одном направлении, ошибки будут нарастать быстрее (от округлой до четности предполагается минимизировать это) (a).
Следуйте этим ссылкам для Описание MSDN:
Math.Floor
, которое округляется вниз к отрицательной бесконечности. Math.Ceiling
, который округляется вверх до нуля. Math.Truncate
, который округляется вверх или вниз к нулю. Math.Round
, который округляется до ближайшего целого числа или заданного числа десятичных знаков. Вы можете указать поведение, если оно точно равноудалено между двумя возможностями, например округлением, чтобы окончательная цифра была четной («Round(2.5,MidpointRounding.ToEven)
» становится равной 2) или так, что она находится дальше от нуля («Round(2.5,MidpointRounding.AwayFromZero)
» становится 3). Следующая диаграмма и таблица могут помочь:
-3 -2 -1 0 1 2 3
+--|------+---------+----|----+--|------+----|----+-------|-+
a b c d e
a=-2.7 b=-0.5 c=0.3 d=1.5 e=2.8
====== ====== ===== ===== =====
Floor -3 -1 0 1 2
Ceiling -2 0 1 2 3
Truncate -2 0 0 1 2
Round(ToEven) -3 0 0 2 3
Round(AwayFromZero) -3 -1 0 2 3
Обратите внимание, что Round
намного мощнее, чем кажется, просто потому, что он может округлить до определенное количество знаков после запятой. Все остальные округляются до нуля десятичными знаками. Например:
n = 3.145;
a = System.Math.Round (n, 2, MidpointRounding.ToEven); // 3.14
b = System.Math.Round (n, 2, MidpointRounding.AwayFromZero); // 3.15
С помощью других функций вы должны использовать метод умножения / деления для достижения такого же эффекта:
c = System.Math.Truncate (n * 100) / 100; // 3.14
d = System.Math.Ceiling (n * 100) / 100; // 3.15
(a) Конечно , эта теория зависит от того, что ваши данные имеют довольно равномерное распределение значений по четным половинам (0,5, 2,5, 4,5, ...) и нечетным половинам (1,5, 3,5, ...).
Если все равны «полузначениям» (например), ошибки будут накапливаться так же быстро, как если бы вы всегда округлялись.
У меня была эта проблема, когда мой SQL-сервер округлялся с 0,5 до 1, пока мое приложение C # этого не делало. Таким образом, вы увидите два разных результата.
Вот реализация с int / long. Это как Java-раунды.
int roundedNumber = (int)Math.Floor(d + 0.5);
Это, вероятно, самый эффективный метод, о котором вы могли бы подумать.
Если вы хотите сохранить его двойным и использовать десятичную точность, тогда это действительно вопрос использования показателей из 10 в зависимости от того, сколько десятичных знаков.
public double getRounding(double number, int decimalPoints)
{
double decimalPowerOfTen = Math.Pow(10, decimalPoints);
return Math.Floor(number * decimalPowerOfTen + 0.5)/ decimalPowerOfTen;
}
Вы можете ввести отрицательный десятичный знак для десятичных точек, и это также слово отлично.
getRounding(239, -2) = 200
У этой записи есть ответ, который вы ищете:
http://weblogs.asp.net/sfurman/archive/2003/03/07/3537.aspx
В основном это то, что он говорит:
Возвращаемое значение
Ближайшее значение числа с точностью, равной цифрам. Если значение находится на полпути между двумя числами, одно из которых четное, а другое - нечетное, то возвращается четное число. Если точность значения меньше цифр, тогда значение возвращается без изменений.
Поведение этого метода следует за стандартом IEEE 754, раздел 4. Этот вид округления иногда называется округлением до ближайшего или округления банкира , Если цифры равны нулю, этот вид округления иногда называют округлением к нулю.