Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/4: Рейтинг темы: голосов - 4, средняя оценка - 5.00
0 / 0 / 1
Регистрация: 04.05.2012
Сообщений: 23

Parallel.For: Зачастую t1 не равно t2 и соответственно не равны Sum1 и Sum2

02.12.2013, 07:07. Показов 847. Ответов 13
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Небольшой вопрос по использованию Parallel.for.
Задача проста...

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   int Min = 0,
       Max = 1000,
       t1 = 0, 
       t2 = 0;
 
   double Sum1 = 0,
          Sum2 = 0;
 
   for (int i = Max + 1; --i > Min - 1; )
   {
       for (int j = Max + 1; --j > Min - 1; t1++)
           Sum1 += Math.Atan(i * j) / (i + 1)
                 * Math.Atan(i * j) / (j + 1);
                    
   }
 
   Parallel.For(Min, Max + 1, i =>
   {
        for (int j = Max + 1; --j > Min - 1; t2++)
            Sum2 += Math.Atan(i * j) / (i + 1)
                  * Math.Atan(i * j) / (j + 1);
   });
но почему то зачастую t1 не равно t2 и соответственно не равны Sum1 и Sum2. Собственно вопрос: почему? и как этого избежать? Заранее спасибо)
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
02.12.2013, 07:07
Ответы с готовыми решениями:

Построить новый массив с элементами, значения которых соответственно равны
Дан массив z1, z2, z3,…, z3n. Построить новый массив с элементами, значения которых соответственно равны z1, z4, …, z3n-2, z2, z5, …,...

Построить новый массив с элементами, значения которых соответственно равны a1, an+1, a2, an+2,…, an, a2n
Дан массив a1, a2, a3,…, a2n. Построить новый массив с элементами, значения которых соответственно равны a1, an+1, a2, an+2,…, an, a2n.

Построить вектор, элементы которого соответственно равны произведениям элементов строк
Дана матрица: Написать программы построения вектора b1, b2, ..., bm, элементы которого соответственно равны...

13
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
02.12.2013, 10:14
У вас гонка за Sum2.
Чтобы избежать этого, вам нужно атомарно увеличивать Sum2. Например, это можно сделать заменив обычное сложение на Interlocked.Add
1
0 / 0 / 1
Регистрация: 04.05.2012
Сообщений: 23
02.12.2013, 14:23  [ТС]
Понял проблему, в общих чертах. Но предложенное решение ( Interlocked.Add ) не работает с типом double. Есть какое то решение? В гугле нагуглить не смог.
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
02.12.2013, 14:50
Ох, вы правы. Тогда можно воспользоваться Interlocked.CompareExchange:
C#
1
2
3
4
5
6
7
     double nextResult = Math.Atan(i * j) / (i + 1)
                       * Math.Atan(i * j) / (j + 1);
     double initialValue, computedValue;
     do {
         initialValue = Sum2;
         computedValue = initialValue + nextResult;
     } while (initialValue != Interlocked.CompareExchange(ref Sum2, computedValue, initialValue));
0
0 / 0 / 1
Регистрация: 04.05.2012
Сообщений: 23
02.12.2013, 17:15  [ТС]
К сожалению ваш вариант совсем не решил проблему. Либо я просто чего то не понял. Немного поэкспериментировав я получил более стабильный вариант, но в нем так же случаются отклонения.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//предложенный вариант
Parallel.For(Min, Max + 1, i =>
                {
                    for (int j = Max + 1; --j > Min - 1; t3++)
                    {
                        double nextResult = Math.Atan(i * j) / (i + 1)
                      * Math.Atan(i * j) / (j + 1);
                        double initialValue, computedValue;
                        do
                        {
                            initialValue = Sum3;
                            computedValue = initialValue + nextResult;
                        } while (initialValue != Interlocked.CompareExchange(ref Sum3, computedValue, initialValue));
                    }
                });
 
//модифицированный мной вариант
Parallel.For(Min, Max + 1, i =>
                {
                    double nextResult = 0;
 
                    for (int j = Max + 1; --j > Min - 1; t2++)
                    {
                        nextResult += Math.Atan(i * j) / (i + 1) * Math.Atan(i * j) / (j + 1);
                    }
 
                    double initialValue,
                           computedValue;
                    do
                    {
                        initialValue = Sum2;
                        computedValue = initialValue + nextResult;
                    } while (initialValue != Interlocked.CompareExchange(ref Sum2, computedValue, initialValue));
                });
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
02.12.2013, 19:18
Цитата Сообщение от Simoniys Посмотреть сообщение
Немного поэкспериментировав я получил более стабильный вариант, но в нем так же случаются отклонения.
Странно, у меня ваш вариант стабильно дает один и тот же результат.
Как вы проверяете отклонения?

Возможно проблема в том, что вы не учитываете особенности операций с плавающей запятой.
Строго говоря для типа double в общем НЕ выполняется (a+b)+c = a+(b+c). Порядок операндов при сложении имеет значение.
0
0 / 0 / 1
Регистрация: 04.05.2012
Сообщений: 23
02.12.2013, 20:25  [ТС]
Действительно странно. У меня есть TextBox при нажатии на который у меня вызывается функция:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private void textBox1_MouseClick(object sender, MouseEventArgs e)
        {
            int Min = 0,
                Max = 125,
                t1 = 0,
                t2 = 0;
 
            double Sum1 = 0,
                   Sum2 = 0;
 
            for (int i = Max + 1; --i > Min - 1; )
            {
                for (int j = Max + 1; --j > Min - 1; t1++)
                    Sum1 += Math.Atan(i * j) / (i + 1) * Math.Atan(i * j) / (j + 1);
 
            }
 
            Parallel.For(Min, Max + 1, i =>
            {
                double nextResult = 0;
 
                for (int j = Max + 1; --j > Min - 1; t2++)
                {
                    nextResult += Math.Atan(i * j) / (i + 1) * Math.Atan(i * j) / (j + 1);
                }
 
                double initialValue = 0,
                       computedValue = 0;
                do
                {
                    initialValue = Sum2;
                    computedValue = initialValue + nextResult;
                } while (initialValue != Interlocked.CompareExchange(ref Sum2, computedValue, initialValue));
            });
 
            t1 = t2 = 0;//здесь ставлю точку останова
        }
Ну и собственно трассирую через F5 и сравниваю значения в окне контрольных. Возможно где то здесь я что то не обнуляю, но что именно? Дело в том что ошибка может проявиться после 10 нажатий.
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
02.12.2013, 21:39
Ну так и что, намного различаются значения?
0
0 / 0 / 1
Регистрация: 04.05.2012
Сообщений: 23
02.12.2013, 23:18  [ТС]
Различия в данном случае достаточно не значительны: Последние три значащие цифры далеко после запятой.
Sum1 = 45.587510489502144 (double)
Sum2 = 45.587510489502208 (double)
Проблемка в том, что в дальнейшем, распараллеливание я буду применять для вычисления "Инвариантных моментом Лежандра", а вот там эти три циферки могут изрядно попортить мне точность, чего я собственно хотел бы избежать. Неужели нет возможности параллельных вычислений без потерь? Для меня это, честно говоря, новость.
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
03.12.2013, 09:28
Цитата Сообщение от Simoniys Посмотреть сообщение
Неужели нет возможности параллельных вычислений без потерь?
параллельность тут ни при чём. Скорее всего Sum1 тоже не самый точный результат.
Чтобы увеличить точность при работе с дробными значенями, обычно рекомендуют использовать тип decimal, вместо double.
1
0 / 0 / 1
Регистрация: 04.05.2012
Сообщений: 23
03.12.2013, 12:42  [ТС]
Да согласен. Я не совсем верно выразился. Нужна стабильность Что бы одни и тебе вычисления давали один результат. Почему при использовании параллелизма возникают различные значения? Из-за того что (a+b)+c ! = a+(b+c) ? возможно ли этого избежать? Если я например буду использовать массив в который буду передавать соответствующие значения параллельных потоков, а затем сложу их в прямом порядке? это даст мне выигрыш во времени, без потери "относительной точности"?
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
03.12.2013, 13:08
Цитата Сообщение от Simoniys Посмотреть сообщение
Почему при использовании параллелизма возникают различные значения? Из-за того что (a+b)+c ! = a+(b+c) ?
Скорее всего, да.
Цитата Сообщение от Simoniys Посмотреть сообщение
возможно ли этого избежать? Если я например буду использовать массив в который буду передавать соответствующие значения параллельных потоков, а затем сложу их в прямом порядке? это даст мне выигрыш во времени, без потери "относительной точности"?
Да, ваш вариант приемлем. Даст ли он прирост - это надо проверять.
Еще, как я говорил - можно использовать более точные типы данных.
1
0 / 0 / 1
Регистрация: 04.05.2012
Сообщений: 23
03.12.2013, 15:55  [ТС]
Итог:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 private void textBox1_MouseClick(object sender, MouseEventArgs e)
        {
            int Min = 0,
                Max = 10000,
                t1 = 0,
                t2 = 0;
 
            long Time1,
                 Time2;
            
            Stopwatch sWatch = new Stopwatch();
 
            double[] S;
            
            double Sum1 = 0,
                   Sum2 = 0;
            
            sWatch.Start();
            for (int i = Max + 1; --i > Min - 1; )
            {
                for (int j = Max + 1; --j > Min - 1; t1++)
                    Sum1 += Math.Atan(i * j) / (i + 1) * Math.Atan(i * j) / (j + 1);
 
            }
            Time1 = sWatch.ElapsedMilliseconds;
 
            sWatch.Restart();
            S = new double[Max - Min + 1];
 
            Parallel.For(Min, Max + 1, i =>
            {
                for (int j = Max + 1; --j > Min - 1; t2++)
                {
                    S[i-Min] += Math.Atan(i * j) / (i + 1) * Math.Atan(i * j) / (j + 1);
                }
                
            });
 
            for (int i = S.Length; --i > -1; )
                Sum2 += S[i];
            Time2 = sWatch.ElapsedMilliseconds;
 
            t1 = t2 = 0;
        }
    }
Sum1 187.93178248450576 double
Sum2 187.93178248451187 double
t1 100020001 int
t2 84945418 int
Time1 12892 long
Time2 4711 long

Как видно при 10 000 итераций прирост скорости хороший. Значение немного отличается, но при этом оно стабильно. Насчет decimal еще думаю. Немного смущает тот факт что t1 и t2 имеют различное значение. Или тут тоже имеет место быть гонка и они не отображают реального количества итераций (конкретно t2)?
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
03.12.2013, 17:23
Цитата Сообщение от Simoniys Посмотреть сообщение
Немного смущает тот факт что t1 и t2 имеют различное значение. Или тут тоже имеет место быть гонка и они не отображают реального количества итераций (конкретно t2)?
Да, конечно. Тоже гонка.

Добавлено через 28 минут
PS. Вот на википедии нашел про проблему с порядком операция над числами с плавающей запятой - http://en.wikipedia.org/wiki/F... y_problems
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
03.12.2013, 17:23
Помогаю со студенческими работами здесь

Построение вектора, элементы которого соответственно равны произведениям элементов строк матрицы
Дана матрица,заполненная с помощью функции случайных чисел написать программы построения вектора b1 b2...,b m,элементы которого...

Вывести max и min, которые равны соответственно наибольшему и наименьшему членам последовательности
Помогите найти ошибку пожалуйста. Уловие : Определить процедуру p(n, max, min), n - натуральное число, в теле которой вводится...

Построение вектора b1, b2, bm, элементы которого соответственно равны наименьшим элементам строк матрицы
Дана матрица, заполненная с помощью функции случайных чисел в динамической области памяти, используя алгоритм для общего формирования...

Написать программу построения нового массива с элементами, значения которых соответственно равны
Дан массив а0, а1, а2,…, а2n-1. Написать программу построения нового массива с элементами, значения которых соответственно равны а0, аn,...

Построить вектор, элементы которого соответственно равны сумме элементов каждой строки матрицы
Помогите, пожалуйста. Дана квадратная вещественная матрица размерности n. Построить матрицу вектор (одномерный массив) элементы...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru