Мы обнаружили, что решение Дэвида Б работает лучше всего. Но мы адаптировали его к более общему решению:
list.GroupBy(item => item.SomeProperty)
.Select(group => new List<T>(group))
.ToArray();
upd:
Итак, в конце концов, закругленные ошибки всегда будут преследовать вас, как бы вы ни старались их компенсировать. Следовательно, проблема должна быть атакована, представляя числа точно в десятичной нотации.
Number.prototype.toFixedDown = function(digits) {
var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"),
m = this.toString().match(re);
return m ? parseFloat(m[1]) : this.valueOf();
};
[ 5.467.toFixedDown(2),
985.943.toFixedDown(2),
17.56.toFixedDown(2),
(0).toFixedDown(1),
1.11.toFixedDown(1) + 22];
// [5.46, 985.94, 17.56, 0, 23.1]
Старое ошибочное решение, основанное на компиляции других:
Number.prototype.toFixedDown = function(digits) {
var n = this - Math.pow(10, -digits)/2;
n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56"
return n.toFixed(digits);
}
Результирующий тип остается числом ...
/* Return the truncation of n wrt base */
var trunc = function(n, base) {
n = (n / base) | 0;
return base * n;
};
var t = trunc(5.467, 0.01);
Рассмотрим , используя двойную тильду: ~~
.
Возьмите номер. Умножьте значащими цифрами после десятичного знака, чтобы обрезать в нулевые места с помощью ~~
. Разделите этот множитель обратно. Прибыль.
function truncator(numToTruncate, intDecimalPlaces) {
var numPower = Math.pow(10, intDecimalPlaces); // "numPowerConverter" might be better
return ~~(numToTruncate * numPower)/numPower;
}
Я пытаюсь сопротивляться завершению вызова ~~
в parens;
alert(truncator(5.1231231, 1)); // is 5.1
alert(truncator(-5.73, 1)); // is -5.7
alert(truncator(-5.73, 0)); // is -5
EDIT: Оглядываясь назад, я непреднамеренно также обрабатывал случаи, чтобы округлить слева от десятичного числа.
alert(truncator(4343.123, -2)); // gives 4300.
Логика немного странная, ища это использование и может извлечь выгоду из быстрого рефакторинга. Но он все еще работает. Лучше повезло, чем хорошо.
if(isNAN(result) result = 0;
Зависит от поведения, которое вы хотите.
– Jeremy Witmer
22 April 2013 в 23:18
Math
с этим и проверяете NaN-s перед выполнением, это будет просто отлично.
– Barth Zalewski
3 December 2014 в 16:59
Вот код ES6, который делает то, что вы хотите
const truncateTo = (unRouned, nrOfDecimals = 2) => {
const parts = String(unRouned).split(".");
if (parts.length !== 2) {
// without any decimal part
return unRouned;
}
const newDecimals = parts[1].slice(0, nrOfDecimals),
newString = `${parts[0]}.${newDecimals}`;
return Number(newString);
};
// your examples
console.log(truncateTo(5.467)); // ---> 5.46
console.log(truncateTo(985.943)); // ---> 985.94
// other examples
console.log(truncateTo(5)); // ---> 5
console.log(truncateTo(-5)); // ---> -5
console.log(truncateTo(-985.943)); // ---> -985.94
Мне показалось, что я нахожу ответ, используя |
, поскольку он прост и работает хорошо.
truncate = function(number, places) {
var shift = Math.pow(10, places);
return ((number * shift) | 0) / shift;
};
or
ing с помощью 0 означает «просто сохранить то, что у меня уже есть». Делает то, что делает мой ответ ~~
, но с одной побитовой операцией. Хотя это имеет то же ограничение, что и написано: Мы не можем переходить 2 ^ 31 .
– ruffin
12 June 2015 в 19:37
Number.prototype.truncate = function(places) {
var shift = Math.pow(10, places);
return Math.trunc(this * shift) / shift;
};
var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46
truncate(-3.14)
и получу -4
назад, я бы определенно назвал это нежелательным.
– Nick Knowlson
13 August 2013 в 22:34
var a = 65.1
var truncated = Math.floor(a * 100) / 100; // = 65.09
Следовательно, это не правильное решение
– Sanyam Jain
28 December 2017 в 09:44
function toFixed(number, digits) {
var reg_ex = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)")
var array = number.toString().match(reg_ex);
return array ? parseFloat(array[1]) : number.valueOf()
}
var test = 10.123456789
var __fixed = toFixed(test, 6)
console.log(__fixed)
// => 10.123456
Ответ от @kirilloid кажется правильным ответом, однако основной код необходимо обновить. Его решение не заботится о отрицательных числах (что кто-то упоминал в разделе комментариев, но не был обновлен в основном коде).
Обновление этого окончательного тестируемого решения:
Number.prototype.toFixedDown = function(digits) {
var re = new RegExp("([-]*\\d+\\.\\d{" + digits + "})(\\d)"),
m = this.toString().match(re);
return m ? parseFloat(m[1]) : this.valueOf();
};
Пример использования:
var x = 3.1415629;
Logger.log(x.toFixedDown(2)); //or use whatever you use to log
Fiddle: JS Number Round down
PS: недостаточно репо, чтобы прокомментировать это решение.
Усекать с помощью побитовых операторов:
~~0.5 === 0
~~(-0.5) === 0
~~14.32794823 === 14
~~(-439.93) === -439
Я нашел проблему: учитывая следующую ситуацию: 2.1 или 1.2 или -6.4
Что делать, если вы хотите всегда 3 десятичных знака или два или wharever, так что вам нужно закончить ведущие нули справа
// 3 decimals numbers
0.5 => 0.500
// 6 decimals
0.1 => 0.10000
// 4 decimales
-2.1 => -2.1000
// truncate to 3 decimals
3.11568 => 3.115
Это фиксированная функция Ника Ноулсона
function truncateDecimals (num, digits)
{
var numS = num.toString();
var decPos = numS.indexOf('.');
var substrLength = decPos == -1 ? numS.length : 1 + decPos + digits;
var trimmedResult = numS.substr(0, substrLength);
var finalResult = isNaN(trimmedResult) ? 0 : trimmedResult;
// adds leading zeros to the right
if (decPos != -1){
var s = trimmedResult+"";
decPos = s.indexOf('.');
var decLength = s.length - decPos;
while (decLength <= digits){
s = s + "0";
decPos = s.indexOf('.');
decLength = s.length - decPos;
substrLength = decPos == -1 ? s.length : 1 + decPos + digits;
};
finalResult = s;
}
return finalResult;
};
Я думаю, что эта функция может быть простым решением:
function trunc(decimal,n=2){
let x = decimal + ''; // string
return x.lastIndexOf('.')>=0?parseFloat(x.substr(0,x.lastIndexOf('.')+(n+1))):decimal; // You can use indexOf() instead of lastIndexOf()
}
console.log(trunc(-241.31234,2));
console.log(trunc(241.312,5));
console.log(trunc(-241.233));
console.log(trunc(241));
Lodash имеет несколько методов полезности Math, которые могут round , floor и ceil число до заданной десятичной точности. Это исключает конечные нули.
Они занимают интересный подход, используя показатель числа. По-видимому, это исключает проблемы округления.
(Примечание: func
- Math.round
или ceil
или floor
в коде ниже)
// Shift with exponential notation to avoid floating-point issues.
var pair = (toString(number) + 'e').split('e'),
value = func(pair[0] + 'e' + (+pair[1] + precision));
pair = (toString(value) + 'e').split('e');
return +(pair[0] + 'e' + (+pair[1] - precision));
Number.prototype.trim = function(decimals) {
var s = this.toString();
var d = s.split(".");
d[1] = d[1].substring(0, decimals);
return parseFloat(d.join("."));
}
console.log((5.676).trim(2)); //logs 5.67
Хорошее однострочное решение:
function truncate (num, places) {
return Math.trunc(num * Math.pow(10, places)) / Math.pow(10, places);
}
Затем назовите его с помощью:
truncate(3.5636232, 2); // returns 3.56
truncate(5.4332312, 3); // returns 5.433
truncate(25.463214, 4); // returns 25.4632
Здесь я беру тему:
convert.truncate = function(value, decimals) {
decimals = (decimals === undefined ? 0 : decimals);
return parseFloat((value-(0.5/Math.pow(10, decimals))).toFixed(decimals),10);
};
Это всего лишь несколько более сложная версия
(f - 0.005).toFixed(2)
Вы можете исправить округление, вычитая 0,5 для toFixed, например
(f - 0.005).toFixed(2)
Вот простая, но работающая функция для усечения числа до двух знаков после запятой.
function truncateNumber(num) {
var num1 = "";
var num2 = "";
var num1 = num.split('.')[0];
num2 = num.split('.')[1];
var decimalNum = num2.substring(0, 2);
var strNum = num1 +"."+ decimalNum;
var finalNum = parseFloat(strNum);
return finalNum;
}
Тот, который является признаком в качестве решения, является лучшим решением, которое я нашел до сегодняшнего дня, но имеет серьезную проблему с 0 (например, 0.toFixedDown (2) дает -0.01). Поэтому я предлагаю использовать это:
Number.prototype.toFixedDown = function(digits) {
if(this == 0) {
return 0;
}
var n = this - Math.pow(10, -digits)/2;
n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56"
return n.toFixed(digits);
}
просто для указания простого решения, которое сработало для меня
, преобразовать его в строку, а затем повторно использовать его ...
var number = 123.45678;
var number_s = '' + number;
var number_truncated_s = number_s.match(/\d*\.\d{4}/)[0]
var number_truncated = parseFloat(number_truncated_s)
Его можно сокращать до
var number_truncated = parseFloat(('' + 123.4568908).match(/\d*\.\d{4}/)[0])
Вот что я использую:
var t = 1;
for (var i = 0; i < decimalPrecision; i++)
t = t * 10;
var f = parseFloat(value);
return (Math.floor(f * t)) / t;
@ Ответ Соберта может быть улучшен с помощью Math.trunc
, который усекает вместо округления.
Существует разница между округлением и усечением. Усечение - это явно поведение, которое ищет этот вопрос. Если я вызову truncate (-3.14) и получаю -4 назад, я бы определенно назвал это нежелательным. - @NickKnowlson
var a = 5.467; var truncated = Math.trunc(a * 100) / 100; // = 5.46
var a = -5.467; var truncated = Math.trunc(a * 100) / 100; // = -5.46
Math.trunc
, но вместо 9.28 * 100
есть 927.9999
, а не 928
. Возможно, вы захотите прочитать Опасности плавающей точки
– zurfyx
3 April 2018 в 06:56
1.11.toFixedDown(1) + 22
заканчивается как1.122
вместо23.1
. Также0.toFixedDown(1)
должен произвести0
, но вместо этого он создает-0.1
. – Nick Knowlson 12 March 2014 в 00:41(-10.2131).toFixedDown(2) // ==> 10.21
. – usandfriends 15 July 2014 в 17:20(1e-7).toFixedDown(0) // ==> 1e-7
. Это для1e-(>=7)
(например:1e-8
,1e-9
, ...). – usandfriends 15 July 2014 в 17:38