Удвоения быстрее, чем числа с плавающей запятой в C#?

Я пишу приложение, которое читает большие массивы чисел с плавающей запятой и выполняет с ними некоторые простые операции. Я использую числа с плавающей запятой, потому что думал, что это будет быстрее, чем удвоение, но после некоторого исследования я обнаружил, что в этой теме есть некоторая путаница. Кто-нибудь может уточнить это?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
53
0
16 691
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Это указывает на то, что числа с плавающей запятой немного быстрее, чем удвоения: http://www.herongyang.com/cs_b/performance.html

В общем, каждый раз, когда вы проводите сравнение производительности, вы должны учитывать какие-либо особые случаи, например, требует ли использование одного типа дополнительных преобразований или обработки данных? Они складываются и могут опровергать такие общие тесты.

Я не знаю, доверяю ли я тестам какого-нибудь чувака, где точность падает до менее секунды. Почему бы не написать более крупный (и более реалистичный тест с большим количеством различных типов тестов) и дать ему поработать несколько минут?

Nik Reiman 01.10.2008 22:30

Я попробовал этот тест, и в сборке Release они занимают одинаковое время обработки.

Joan Venge 06.01.2009 21:59

Плавающие должны быть быстрее в 32-битной системе, но профилируйте код, чтобы убедиться, что вы оптимизируете правильные вещи.

@Steven A. Lowe: Я бы заметил, что в некоторых 32-битных системах внутренне не хватает 32-битных чисел с плавающей запятой! Следовательно, снижение общей производительности. Ваше утверждение верно с точки зрения пропускной способности памяти, поскольку float подходит лучше, чем double.

user7116 01.10.2008 22:16
Ответ принят как подходящий

Короткий ответ: «используйте ту точность, которая требуется для получения приемлемых результатов».

Ваша единственная гарантия заключается в том, что операции, выполняемые с данными с плавающей запятой, выполняются по крайней мере в члене выражения наивысшей точности. Таким образом, умножение двух плавать выполняется по крайней мере с точностью плавать, а умножение плавать и двойной должно выполняться как минимум с двойной точностью. Стандарт гласит, что «операции [с плавающей точкой] могут выполняться с более высокой точностью, чем тип результата операции».

Учитывая, что JIT для .NET пытается оставить ваши операции с плавающей запятой с требуемой точностью, мы можем взглянуть на документацию Intel для ускорения наших операций. На платформе Intel ваши операции с плавающей запятой могут выполняться с промежуточной точностью 80 бит и преобразовываться с точностью до требуемой.

В руководстве Intel по операциям с плавающей запятой C++ 1 (извините, есть только мертвое дерево) они упоминают:

  • Use a single precision type (for example, float) unless the extra precision obtained through double or long double is required. Greater precision types increase memory size and bandwidth requirements. ...
  • Avoid mixed data type arithmetic expressions

Этот последний пункт важен как вы можете замедлить себя с помощью ненужных бросков в / из поплавка и удвоения, что приводит к JIT-коду, который просит x87 отбрасывать его от своего 80-битного промежуточного формата между операциями!

1. Да, там написано C++, но стандарт C# плюс знание CLR позволяет нам знать, что информация для C++ должна быть применима в этом случае.

На стороне примечания (не имеющего отношения к вашему ответу), использует ли JIT .net x87? Intel уговаривала всех на время отказаться от нее в пользу SSE.

Mike F 01.10.2008 22:34

@Mike F: насколько я могу судить, он не выбирает операции SSE. Не цитируйте меня по этому поводу, это только из того, что я видел в своем коде с помощью JIT. Я могу спросить микрософту и узнать.

user7116 01.10.2008 22:35

@sixlettervariables: Мне было бы очень интересно услышать ответ, если вы его когда-нибудь получите и захотите опубликовать его здесь.

Mike F 01.10.2008 22:43

Я помню, как член команды x86 JIT объяснял свою логику в этом вопросе. Он сказал, что они используют x87 для операций с плавающей запятой, а не SSE, поскольку SSE быстрее для одних операций и медленнее для других. Поскольку JIT не пытается векторизовать математику с плавающей запятой, они предпочли создать действительно хороший JIT x87, а не разделить свои усилия.

Eloff 24.07.2010 00:43

Мне удалось найти ссылку, это Дэвид Нотарио в этом обсуждении для заинтересованных, но он касается JIT в 1.1, поэтому относитесь к нему с большим подозрением: bytes.com/topic/c-sharp/answers/…

Eloff 24.07.2010 00:50

Я согласен, что инструкция для float, double, integer, short и char или даже 1 бит занимает один цикл процессора независимо от типа. Но возникает ли разница, если рассматривать сравнение адресации, локальности, параллельной обработки. Мне кажется, что у обработки двойной точности больше накладных расходов. Сделать настоящий тест не так-то просто. Компиляторы умны и оптимизируют накладные расходы, поэтому реальная проблема может остаться скрытой, если тест выполняет относительно тупую работу.

DeveloperInToronto 20.05.2011 22:38

@DeveloperInToronto: многие операции с плавающей запятой требуют нескольких циклов. И так сделайте несколько целочисленных операций. Кроме того, базовый показатель для сравнения - это даже не «1 цикл», а дробь, поскольку современные процессоры имеют несколько ALU.

Ben Voigt 04.01.2013 18:38

Если узким местом являются операции загрузки и сохранения, то числа с плавающей точкой будут работать быстрее, потому что они меньше. Если вы выполняете значительное количество вычислений между загрузками и хранилищами, оно должно быть примерно одинаковым.

Кто-то еще упомянул об избежании преобразований между float и double и вычислениях, использующих операнды обоих типов. Это хороший совет, и если вы используете какие-либо математические библиотечные функции, которые возвращают двойные значения (например), то сохранить все как двойные значения будет быстрее.

Так обстоит дело с C#, где все математические операции возвращают двойные значения. Для буквальных значений вы можете использовать f и т. д. Для самого значения.

Joan Venge 06.01.2009 21:56

Несколько недель назад я задавал аналогичный вопрос. Суть в том, что для оборудования x86 нет существенной разницы в производительности с плавающей запятой по сравнению с двойными, если только вы не ограничите память или не начнете сталкиваться с проблемой кеширования. В этом случае поплавки обычно имеют преимущество, потому что они меньше.

Текущие процессоры Intel выполняют все операции с плавающей запятой в регистрах шириной 80 бит, поэтому фактическая скорость вычислений не должна варьироваться между числами с плавающей запятой и удвоением.

С арифметикой 387 FPU float работает быстрее, чем double для некоторых длинных итеративных операций, таких как pow, log и т. д. (И только если компилятор правильно устанавливает управляющее слово FPU).

Однако с упакованной арифметикой SSE это имеет большое значение.

Я пишу трассировщик лучей, и замена поплавков на двойные для моего класса Color дает мне ускорение на 5%. Замена векторов с плавающей запятой на двойные еще на 5% быстрее! Довольно круто :)

Это с Core i7 920

Я бы предположил из-за того, что часть вашего кода отбрасывается назад и вперед между float-> double-> float, например. с математическими функциями, которые возвращают double, поэтому за ускорение отвечает устранение приведений; не обязательно, потому что двойники изначально быстрее.

HoboBen 11.10.2010 10:11

Собственно, я беру это обратно. Я только что протестировал простой цикл for, и кажется, по какой-то причине являются удваивается быстрее!

HoboBen 11.10.2010 13:15

Процессор значения не имеет. Независимо от того, делаете ли вы это на медленном или быстром ПК ... улучшение на 5% означает улучшение на 5% :-)

z0mbi3 16.10.2015 00:46

Я всегда думал, что процессоры были оптимизированы или одинаковы, независимо от того, с плавающей точкой или с двойной точностью. В поисках оптимизаций в моих интенсивных вычислениях (множество получений из матрицы, сравнение двух значений) я обнаружил, что числа с плавающей запятой работают примерно на 13% быстрее.

Это меня удивило, но, полагаю, это связано с характером моей проблемы. Я не делаю приведений между float и double в основных операциях, и мои вычисления в основном складываются, умножаются и вычитаются.

Это мой i7 920, работающий под управлением 64-битной операционной системы.

Я только что прочитал «Microsoft .NET Framework-Application Development Foundation 2nd» для экзамена MCTS 70-536, и на странице 4 (глава 1) есть примечание:

NOTE Optimizing performance with built-in types
The runtime optimizes the performance of 32-bit integer types (Int32 and UInt32), so use those types for counters and other frequently accessed integral variables. For floating-point operations, Double is the most efficient type because those operations are optimized by hardware.

Это написано Тони Нортрупом. Я не знаю, авторитет он или нет, но я ожидаю, что официальная книга для экзамена .NET должна иметь некоторый вес. Конечно, это не гарантия. Я просто подумал, что добавлю это к этому обсуждению.

Маттейс,

Ты неправ. 32-разрядная версия намного эффективнее 16-разрядной - в современных процессорах ... Возможно, не с точки зрения памяти, но с точки зрения эффективности 32-разрядная версия - лучший способ.

Вам действительно стоит обновить своего профессора до чего-то более «современного». ;)

Во всяком случае, чтобы ответить на вопрос; float и double имеют одинаковую производительность, по крайней мере, на моем Intel i7 870 (как в теории).

Вот мои измерения:

(Я создал «алгоритм», который я повторил 10 000 000 раз, а затем повторил его 300 раз, и из этого я получил среднее значение.)

double
-----------------------------
1 core  = 990 ms
4 cores = 340 ms
6 cores = 282 ms
8 cores = 250 ms

float
-----------------------------
1 core  = 992 ms
4 cores = 340 ms
6 cores = 282 ms
8 cores = 250 ms

Хм, думаю, ты прав. Возможно, источник, который заставил меня поверить в неправильность вопроса, был неправильным. Я обновлю свой ответ, чтобы удалить обновление (например, отменить обновление моего ответа).

Matthijs Wessels 28.02.2011 11:20

Другие вопросы по теме