Double sum c что это
Enumerable. Sum Метод
Определение
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Вычисляет сумму последовательности числовых значений.
Перегрузки
Вычисляет сумму последовательности значений типа Decimal.
Вычисляет сумму последовательности значений типа Double.
Вычисляет сумму последовательности значений типа Int32.
Вычисляет сумму последовательности значений типа Int64.
Вычисляет сумму последовательности значений Decimal обнуляемого типа.
Вычисляет сумму последовательности значений Double обнуляемого типа.
Вычисляет сумму последовательности значений Int32 обнуляемого типа.
Вычисляет сумму последовательности значений Int64 обнуляемого типа.
Вычисляет сумму последовательности значений Single обнуляемого типа.
Вычисляет сумму последовательности значений типа Single.
Вычисляет сумму последовательности значений типа Single, получаемой в результате применения функции преобразования к каждому элементу входной последовательности.
Вычисляет сумму последовательности значений Single обнуляемого типа, получаемой в результате применения функции преобразования к каждому элементу входной последовательности.
Вычисляет сумму последовательности значений Int64 обнуляемого типа, получаемой в результате применения функции преобразования к каждому элементу входной последовательности.
Вычисляет сумму последовательности значений Int32 обнуляемого типа, получаемой в результате применения функции преобразования к каждому элементу входной последовательности.
Вычисляет сумму последовательности значений Double обнуляемого типа, получаемой в результате применения функции преобразования к каждому элементу входной последовательности.
Вычисляет сумму последовательности значений типа Double, получаемой в результате применения функции преобразования к каждому элементу входной последовательности.
Вычисляет сумму последовательности значений типа Int64, получаемой в результате применения функции преобразования к каждому элементу входной последовательности.
Вычисляет сумму последовательности значений типа Int32, получаемой в результате применения функции преобразования к каждому элементу входной последовательности.
Вычисляет сумму последовательности значений типа Decimal, получаемой в результате применения функции преобразования к каждому элементу входной последовательности.
Вычисляет сумму последовательности значений Decimal обнуляемого типа, получаемой в результате применения функции преобразования к каждому элементу входной последовательности.
Sum(IEnumerable )
Вычисляет сумму последовательности значений типа Decimal.
Параметры
Последовательность значений Decimal, сумму которых требуется вычислить.
Возвращаемое значение
Сумма последовательности значений.
Исключения
Комментарии
Sum(IEnumerable )Метод возвращает нуль, если source не содержит элементов.
См. также раздел
Применяется к
Sum(IEnumerable )
Вычисляет сумму последовательности значений типа Double.
Параметры
Последовательность значений Double, сумму которых требуется вычислить.
Возвращаемое значение
Сумма последовательности значений.
Исключения
Комментарии
См. также раздел
Применяется к
Sum(IEnumerable )
Вычисляет сумму последовательности значений типа Int32.
Параметры
Последовательность значений Int32, сумму которых требуется вычислить.
Возвращаемое значение
Сумма последовательности значений.
Исключения
Комментарии
См. также раздел
Применяется к
Sum(IEnumerable )
Вычисляет сумму последовательности значений типа Int64.
Параметры
Последовательность значений Int64, сумму которых требуется вычислить.
Возвращаемое значение
Сумма последовательности значений.
Исключения
Комментарии
См. также раздел
Применяется к
Sum(IEnumerable >)
Вычисляет сумму последовательности значений Decimal обнуляемого типа.
Параметры
Последовательность значений Decimal обнуляемого типа, сумму которых требуется вычислить.
Возвращаемое значение
Сумма последовательности значений.
Исключения
Комментарии
См. также раздел
Применяется к
Sum(IEnumerable >)
Вычисляет сумму последовательности значений Double обнуляемого типа.
Параметры
Последовательность значений Double обнуляемого типа, сумму которых требуется вычислить.
Возвращаемое значение
Сумма последовательности значений.
Исключения
Комментарии
См. также раздел
Применяется к
Sum(IEnumerable >)
Вычисляет сумму последовательности значений Int32 обнуляемого типа.
Параметры
Последовательность значений Int32 обнуляемого типа, сумму которых требуется вычислить.
Возвращаемое значение
Сумма последовательности значений.
Исключения
Комментарии
См. также раздел
Применяется к
Sum(IEnumerable >)
Вычисляет сумму последовательности значений Int64 обнуляемого типа.
Параметры
Последовательность значений Int64 обнуляемого типа, сумму которых требуется вычислить.
Возвращаемое значение
Сумма последовательности значений.
Исключения
Комментарии
См. также раздел
Применяется к
Sum(IEnumerable >)
Вычисляет сумму последовательности значений Single обнуляемого типа.
Параметры
Последовательность значений Single обнуляемого типа, сумму которых требуется вычислить.
Возвращаемое значение
Сумма последовательности значений.
Исключения
Примеры
В следующем примере кода показано, как использовать функцию Sum(IEnumerable >) для суммирования значений последовательности.
Комментарии
Организовать ввод двух вещественных чисел и операции над ними: сложение, вычитание, умножение и деление
Структуры: арифметические операции (сложение, вычитание, умножение, деление) над комплексными числами
Написать программу, реализующую арифметические операции (сложение, вычитание, умножение, деление).
Разработать модуль, реализующий основные математические операции (сложение, вычитание, умножение, деление) над двумя числами
привет. очень нужна помощь с задачкой: Разработать модуль, реализующий основные математические.
Создание/удаление, ввод/вывод, сложение, вычитание, умножение, деление длинных чисел
Помогите сделать вот такую задачу: Написать библиотеку функций для работы с целыми числами сколь.
Serezha, Microsoft Visual Studio. или CodeBlocks
Добавлено через 2 минуты
Serezha,
Ввод двух вещественных чисел и действия над ними
Не очень хорошо себе это представляю так что прошу помощи Программа должна выполнять – ввести.
Перегрузить такие операции: сложение, вычитание, умножение, деление, сравнение
Создать класс Angle для работы с углами на плоскости, задаваемыми величиной в градусах и минутах.
Операции с коплексными числами (сложение, вычитание, умножение, деление, модуль)
Операции с коплексными числами(сложение,вычитание, умножение, деление, модуль).Помогите исправить.
Операции над матрицами-сложение, вычитание, умножение на число
Здравствуйте,помогите пожалуйста по такой проблемке-в С++ надо создать матрицу и действия над.
c#: sum of two double numbers problem [duplicate]
Hi. I’ve got following problem:
for decimal is correct:
Why result for double is wrong?
7 Answers 7
For values which are «naturally exact decimals» it’s good to use decimal. This is usually suitable for any concepts invented by humans: financial values are the most obvious example, but there are others too. Consider the score given to divers or ice skaters, for example.
For values which are more artefacts of nature which can’t really be measured exactly anyway, float/double are more appropriate. For example, scientific data would usually be represented in this form. Here, the original values won’t be «decimally accurate» to start with, so it’s not important for the expected results to maintain the «decimal accuracy». Floating binary point types are much faster to work with than decimals.
Short answer: floating point representation (such as «double») is inherently inaccurate. So is fixed point (such as «decimal»), but the inaccuracy in fixed-point representation is of a different kind. Here’s one short explanation: http://effbot.org/pyfaq/why-are-floating-point-calculations-so-inaccurate.htm
You can google for «floating point inaccuracy» or so for more.
It isn’t exactly wrong. It’s the closest decimal representation to the binary floating-point number that results from the sum.
The problem is that IEEE floats cannot represent 43.65 + 61.11 exactly, due to the use of a binary mantissa. Some systems (such as Python 2.7 and Visual C++’s standard I/O libraries) will round to the simplest decimal that resolves to the same binary, and will print the expected 104.76. But all these systems arrive at exactly the same answer internally.
Interestingly, decimal notation can finitely represent any finite binary fraction, whereas the opposite doesn’t hold. If humans had two fingers and computers used ten-state memory, we wouldn’t have this problem. 🙂
Because double uses a fractional model. Any number
I disagree that floats or doubles are more or less accurate than decimal representations. They are as accurate as you choose to have precision. They are a different representation however, and different numbers can be expressed wholey than in base 10.
Decimal stores numbers in base 10. That will probably give you the result you expect
Decimal arithmetic is well-suited for base-10 representations of numbers, as base-10 numbers can be exactly represented in decimal. (Which is why currency is always stored in currency appropriate classes, or stored in int with a scaling factor to represent ‘pennies’ or ‘pence’ or other similar decimal currency.)
Note this simple program and output:
Можно ли сложить N чисел типа double наиболее точно?
Прошлая статья рассказала о двух способах сложения двух двоичных чисел с плавающей запятой без потери точности. Чтобы добиться этого, мы представили сумму c=a+b в виде двух чисел (s,t)=a+b, причём таких, что s — наиболее близкое к a+b точно-представимое число, а t=(a+b)-s — это отсекаемая в результате округления часть, составляющая точную погрешность. У читателей был вопрос: а можно ли достаточно точно сложить массив чисел типа double? Оказывается, можно! Но только, вероятно, не всегда и не абсолютно… и не алгоритмом Кэхэна, который тогда вспоминали в комментариях. За подробностями прошу под кат, где мы и найдём приложение тому, о чём я рассказал в прошлый раз.
Вступление
Кому не терпится получить результат, листайте сразу вниз к разделу «Таблицы» — этот раздел можно понять без чтения теории и многословной методики тестирования. А здесь начинается описание проблемы.
Традиционно, полное содержание статьи также доступно в форме презентации с закадровым голосом:
Дело в том, что абсолютно точно сложить N чисел типа double (binary64 в IEEE-754) с сохранением суммы в типе double не получится в силу самой специфики формата с плавающей запятой. Если мы возьмём арифметику с плавающей запятой с бесконечной точностью (или даже воспользуемся рациональными числами), то при достаточном объёме памяти получим абсолютно точную сумму S массива чисел X[N]. Но эту абсолютно точную сумму нужно будет всё равно округлить к ближайшему числу типа double. Назовём эту округлённую сумму S’. Если вспомнить функцию RN(x) из предыдущей статьи, которая выполняет округление произвольного вещественного x «к ближайшему чётному», то можно сказать, что S’=RN(S), поэтому |S-S’| ≤ 0.5ulp (т. е. ошибка составляет не более половины значения младшего бита). Таким образом, об абсолютной точности мы говорить не можем, но мы будем называть число S’ — «наиболее точной суммой» (из возможных). Поэтому переформулируем наш вопрос иначе: можно ли сложить числа X[N] так, чтобы получить наиболее точную сумму S’, не пользуясь длинной арифметикой, а оставаясь лишь в рамках операций сложения с double?
Да! На случайном наборе чисел этого, вероятно, можно добиться. Я покажу один алгоритм, который мне не удалось «завалить», хотя в теории, наверное, можно придумать какие-то особенные тесты, чтобы он ошибся хотя бы на 1ulp и выдал бы неправильно хотя бы последний бит результата. Всего мы рассмотрим три алгоритма и сравним их между собой через абсолютно точную сумму S, округлённую до наиболее точной суммы S’.
Нам понадобятся два алгоритма из предыдущей статьи, и сейчас мы должны дать им названия. Я буду пользоваться синтаксисом C++, уверен, это не вызовет трудностей с переводом у любого читателя.
Первый алгоритм для двух чисел
Напомню, эти алгоритмы возвращают два числа: наиболее близкую к реальной сумму s=RN(a+b) и точную погрешность t=(a+b)-s. Данный алгоритм работает правильно только при условии |a|≥|b|, если сумма RN(a+b)≠∞.
s = RN (a+b);
z = RN (s-a);
t = RN (b-z);
return (s, t);
Я запрограммировал его на C++ вот так:
Не забудьте, что при компилировании подобного кода нельзя применять флаги агрессивной оптимизации вычислений с плавающей запятой, потому что переставлять порядок вычислений здесь категорически нельзя. Также мне неизвестно, будут ли работать подобные конструкции на GPU, так как раньше (по крайней мере, на заре их применения) они могли обрабатывать числа с плавающей запятой даже близко не по Стандарту. О текущем состоянии дел мне неизвестно, прошу знающих читателей подсказать в комментариях.
Второй алгоритм для двух чисел
Этот алгоритм работает при любом соотношении между и
, но по-прежнему RN(a+b)≠∞. Вместо 3-х операций здесь их 6.
s = RN (a+b);
b’ = RN (s-a);
a’ = RN (s-b’);
d_b = RN (b-b’);
d_a = RN (a-a’);
t = RN (d_a+d_b);
return (s, t)
В моём исполнении на C++ выглядит так:
Теперь рассмотрим какие бывают варианты сложения нескольких чисел из массива. Сразу предупреждаю, что их очень много, но я взял два универсальных и наиболее интересных из книги [1], которые действительно хорошо себя показывают. На остальные алгоритмы, если вам интересно, авторы упомянутой книги дают ряд ссылок.
Обзор алгоритмов сложения
Задача. Задан массив X[N] типа double, требуется отыскать сумму всех чисел в этом массиве, сумма имеет тот же тип double.
Ниже по тексту будут представлены мои варианты реализации алгоритмов с описанием (где оно требуется). Все реализации будут опираться на псевдоним для массива чисел типа double:
Алгоритм 0. Абсолютно точная и наиболее точная сумма
Этот алгоритм нужен только для проверки остальных, его практический смысл лично для меня почти полностью отсутствует. Чтобы посчитать сумму чисел точно, нужна арифметика с бесконечной точностью. Это может быть длинная арифметика с плавающей запятой, а может быть длинная арифметика рациональных чисел. Я выбрал последнюю. Взял библиотеку MPIR (можно было взять и GMP) и тип данных mpq_t. Написанный в скрытом тексте код выдаёт наиболее точную сумму S’, получаемую из абсолютно точной суммы S путём правильного округления. Пропустите скрытый текст, если вы не знакомы с внутренним устройством формата double, это не помешает вам понять остальной материал.
Если нет цели получить максимальную скорость вычислений, то код может быть написан очень прямолинейно, однако далее возникает проблема. Функция mpq_get_d из библиотеки MPIR округляет число вниз, просто отрезая «лишнее» (а другой функции округления там нет). Нам нужно округлить по правилу «к ближайшему чётному», а для этого приходится совершать «танцы с бубном» над битовым представлением чисел типа double. Поэтому в коде ниже есть UB, будьте внимательны.
Алгоритм 1. Наивное суммирование
Очевидный алгоритм и, пожалуй, наиболее быстрый и просторный для оптимизаций компилятора выглядит вот так:
Здесь нечего пояснять.
Алгоритм 2. Kahan
Схема работы алгоритма основана на первом методе сложения двух чисел без потери точности из предыдущей статьи. «Хвостик» , который получается в результате сложения текущей суммы s и очередного слагаемого, добавляется к следующему слагаемому (у=x+c), как бы компенсируя потери. Иными словами, мы не выбрасываем потерянные биты после операции сложения (s+y) на каждом шаге, а пытаемся «спасти» их, добавляя их на следующем шаге.
Внимательный читатель вспомнит, что алгоритм s=fast_two_sum(c, s, y) работает корректно только когда |s|≥|y|, что не обязательно будет именно так для беспорядочной последовательности чисел из исходного массива X. Тем не менее, компенсационные способности данного алгоритма перекрывают ошибочное срабатывание для случаев |s| 51 ulp). А вот следующий алгоритм выдаст в этом случае правильный ответ.
Алгоритм 3. Rump–Ogita–Oishi
Разумный вопрос: а что если вместо первого алгоритма сложения двух чисел из предыдущей статьи взять второй, который безразличен к порядку этих чисел? Этот подход применяется в алгоритме Rump–Ogita–Oishi и даёт такой код:
Однако здесь авторы алгоритма решили складывать «хвостики» в отдельную переменную, что, в общем-то, логично. В конце выполняем сложение итоговой суммы и суммы всех «хвостиков». Данный алгоритм можно представить себе так, как будто мы суммируем числа не в одной переменной типа double, а как бы удваиваем её, получая своего рода «double-double», в котором не 52, а 104 бита дробной части мантиссы. Чтобы «сломать» такой алгоритм, нужно чтобы погрешность «закрыла» 52 бита. Сделать это обычными бытовыми задачами практически нереально, если только вы не складываете триллионы чисел. Впрочем, это лишь домыслы автора текста. Если можете «завалить» алгоритм, прошу показать тест в комментариях (см. этот комментарий, но это не бытовой тест).
Тестирование
Замечание о методике и способе вывода погрешности
Я прошу прощения за многословное описание методики тестирования и преподнесения результата, но если его не сделать, то найдётся очень много скептиков, которые скажут, что я что-то не то протестировал и получил не те данные, какие они получили у себя. А этим объяснением я снимаю с себя всякую ответственность за несовпадения, которые обязательно будут.
Читатель понимает, что величина N может быть произвольной, так же как произвольными могут быть числа в массиве. Поэтому совершенно ясно, что любой обзор работы алгоритмов на практике будет субъективным и неполным. Какое распределение чисел X[i] выбрать? Какими выбрать верхнюю и нижнюю границы суммируемых чисел? Сколько чисел взять для получения репрезентативного результата? Сколько случайных тестов нужно для вычисления адекватной средней погрешности?
Видите в какой трудной ситуации находится обзорщик? Стоит что-нибудь сделать неправильно, читатель найдёт к чему придраться «со своей колокольни». Поэтому я заранее предупреждаю, что мой обзор будет обусловлен исключительно моими предпочтениями выбора тестов. Они описаны рядом с таблицами ниже. Если вам нужны другие результаты (а результаты можно получить любые, всё зависит от степени предвзятости экспериментатора), вы можете создать другие тесты 🙂
Второе предупреждение: как подавать результат? В каких единицах его будет удобнее всего принять читателям, не нуждающимся в детальном научном исследовании? Ну, допустим, я дам вам абсолютную погрешность, которая вычисляется по формуле
где — сумма, полученная алгоритмами 1–3, а
— наиболее точная сумма, полученная алгоритмом 0.
Но и она будет представлять из себя числа, порядки которых будут очень маленькими и трудными для восприятия через ощущения человека. Смотрите сами: относительная погрешность 1.23456e-10%. Удобно?
Чтобы получить погрешность в ulp, нужно посчитать выражение
На моём любимом языке UB++ функция ulp(x) для double вычисляется вот так:
Таблицы
Каждый алгоритм прогонялся на 100 тестах. Один тест — это массив X[N] из чисел типа double. При этом получалось два вида погрешностей: средняя по всем 100 тестам и максимальная по ним же. Оба эти числа указаны в каждой ячейке таблицы: сверху — средняя, снизу — максимальная погрешность. Измерение погрешности ведётся в ulp относительно наиболее точной суммы, полученной абсолютно точным алгоритмом.
Помимо массива X[N], через алгоритм также одновременно прогонялись два других массива, состоящие из этих же чисел. Один из них упорядочен по возрастанию абсолютного значения, а второй — по убыванию.
Первый набор тестов: равномерно распределённые случайные числа на интервале [1,2) в количестве N=1000. Пояснения к символам «
21
0
0
14
0
0
19
0
0
» говорит, что числа в массиве расположены хаотично. Символ «↑» — упорядочены по возрастанию. Символ «↓» — по убыванию. Верхнее число в ячейке — средняя погрешность на 100 тестах, нижнее — максимальная на них же. Как понять, например, число 19 в таблице? Оно значит, что если упорядочить 100 разных массивов по убыванию и на каждом запустить алгоритм, то максимальная погрешность на этих тестах составит 19ulp, то есть, грубо говоря, 4-5 битов «потеряли». В десятичных цифрах это будет 1-2 цифры. Если учесть, что число типа double держит почти 16 десятичных цифр, то потерю 2-х цифр в бытовых задачах можно считать несущественной. При этом в среднем на этих 100 тестах погрешность составила 4,5ulp, то есть почти одну десятичную цифру.
Теперь случайным образом назначим знак «минус» всем нашим случайным числам из интервала [1,2), чтобы положительных чисел и отрицательных стало поровну (в вероятностном смысле). Ещё к нашим символам в первом столбце таблицы мы добавляем «±» с очевидным смыслом.
7936
0
0
2560
0
0
11776
0
0
Вот это да! Разрешили числам быть отрицательными и тут же у наивного алгоритма, что называется, почва ушла из под ног. Погрешность в 11776 ulp эквивалентна потере 4-5 десятичных цифр (13-14 битов из 52 битов дробной части мантиссы). Остальные алгоритмы по-прежнему выдают наиболее точную сумму.
562
0
0
473
0
0
482
0
0
38889
0
0
33965
0
0
36513
0
0
Перейдём к более показательному интервалу [1e-10, 1e+10) и возьмём сразу N=10 6 чисел, только генерация чисел выполняется не равномерно по интервалу, а равномерно по множеству всех возможных чисел типа double на этом интервале. На целочисленном интервале [0x3ddb7cdfd9d7bdbb, 0x4202a05f20000000) (это битовая запись чисел 1e-10 и 1e+10 в формате double) выбирается целое число , которое представляет собой битовую последовательность. Эту битовую последовательность мы интерпретируем как число
типа double, и именно это число
считаем случайным в указанном смысле. Поясню, зачем так делается. Если брать равномерное распределение чисел на математическом интервале [1e-10, 1e+10), то в основном будут попадаться числа, близкие к 1e+10, потому что их больше всего. Их в 10 раз больше, чем чисел, близких к 1e+9, а этих, в свою очередь, в 10 раз больше чем чисел, близких к 1e+8 и так далее. Если же брать числа из множества точно-представимых чисел типа double, выборка будет более репрезентативной, потому что в ней будут самые разные числа с самыми разными экспонентами. А мне это и нужно.
4662
0
0
111
0
0
7915
0
0
8221
21
0
861
1
0
1736
0
0
Как видим, ситуация стала хуже, потому что числа очень разные и ясно, что их сумма будет давать гораздо большую погрешность. Здесь даже алгоритм Кэхэна начал ошибаться. А последний алгоритм всё ещё держится.
Далее у нас экспоненциальное распределение с параметром в количестве чисел N=1000. Та же картина: пока числа имеют один знак — всё в целом неплохо. Когда мы назначаем половине всех чисел знак «минус», ситуация меняется.
19
1
0
11
1
0
26
0
0
1650
23
0
422
6
0
548
0
0
Напоследок посмотрим на нормальное распределение для N=1000 чисел.
483
61
0
243
19
0
734
0
0
Мы видим, что если есть отрицательные числа, то наивный алгоритм начинает складывать совсем плохо. Возникает вопрос: что если складывать отдельно отрицательные числа, отдельно положительные, а затем сложить обе суммы? Ничего не будет кроме того, что станет хуже:
2336
50048
2496
66432
480
99200
Такая вот картина, друзья. Я провёл намного больше тестов, пока работал над статьёй, и сделал для себя следующие выводы.
Другие приложения
У алгоритмов точного сложения двух чисел из предыдущей статьи есть и другие приложения, которые я надеюсь рассмотреть в последующих обзорах. Это вычисление скалярного произведения и значения полинома в точке. Хотя, возможно, читатель уже сам видит, как применить туда эти алгоритмы. Проблема возникает только с корректным промежуточным умножением двух чисел. И я бы не сказал, что это прямо-таки простая тема. Моя мотивация писать продолжение зависит от вашего интереса.
Благодарю за внимание и творческих вам успехов!