LINUX.ORG.RU

Сложение с переполнением в Python

 , ,


0

2

Собственно как сделать и желательно чтобы быстро работало. Пример того что хочется получить (8-битные числа складываем):

250+25=19
В том же условном C++ такое можно получить, например, так:
#include <iostream>

using namespace std;

int main()
{
    unsigned char a=250;
    unsigned char b=25;
    unsigned char c=a+b;
    cout << int(c) << endl;
    return 0;
}
По идее это должно аппаратно быстро выполняться, а в питоне приходит на ум только такая дикая конструкция:
a = 250
b = 25
if a+b > 255:
    c = b-256+a
else:
    c = a+b
print(c)
Однако, по идее такой кодец будет тормозить, когда надо будет считать такие числа в огромных количествах (скажем 20 000 000). Как пример, на моей машине код
#include <iostream>

using namespace std;

int main()
{
    unsigned char a=250;
    unsigned char b=25;
    unsigned char c;
    for(int i=0; i<20000000;i++){
        c=a+b;
        a=c;
    }
    cout << int(c) << endl;
    return 0;
}
Выполняется 0m0.122s Если увеличить в 100 раз, то 0m6.534s, из чего можно предположить что полной оптимизации с предварительным расчетом всего цикла не происходит. Однако, с питоном всё не просто плохо, а ужасно:
a = 250
b = 25
i = 0
c = 0
while i < 20000000:
    if a + b > 255:
        c = b - (256 - a)
    else:
        c = a + b
    a = c
    i = i+1
print(c)
Выполняется целых 0m4.120s Ждать времени выполнения расчета для 2млрд чисел у меня честно даже нет желания, т.к. по грубым прикидкам это будет 6 минут. Итого питон грубо говоря тормозит в 20 раз, что не есть хорошо. Конечно, я понимаю, что питон медленный, т.к. интерпретируемый, но что-то мне подсказывает что if в данном случае помогает ему быть медленней в пару раз. Как можно оптимизировать код на питоне?

★★★★★

Последнее исправление: peregrine (всего исправлений: 1)

Напиши сложение на сишке (можно для вектора) и забинди, быстрее что-либо на нативном питоне врядли будет работать

yoghurt ★★★★★
()
a = 250
b = 25
print((a + b) % 256)

Мб я не понял что-то? Зачем писать числодробилки на чистом питоне и мерять производительность?

Octagon
()
Ответ на: комментарий от Octagon

О, спасибо всем, кто отписался в треде. Числодробилку писать не надо, просто писать скрипт для обработки изображений при том, на уровне посмотреть, как оно работает на питоне гораздо быстрее и проще чем на крестах, но ждать по несколько секунд для одного изображения несколько раздражает, тем более там таких операций не мало, всё же, там одна картинка формируется из нескольких других некоторым хитрым образом. После тестирования алгоритма перепишу всё на C++, возможно даже с какой-нибудь cuda или OpenCL, чтобы это дело очень быстро работало.

peregrine ★★★★★
() автор топика
Последнее исправление: peregrine (всего исправлений: 1)
>>> x = np.uint8(250)
>>> y = np.uint8(25)
>>> x + y
__main__:1: RuntimeWarning: overflow encountered in ubyte_scalars
19

Должно быть быстро, но проверь

Crocodoom ★★★★★
()
Ответ на: комментарий от slovazap

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

>>> x = np.uint8([250, 251, 252, 253, 254])
>>> y = np.uint8([25, 24, 23, 22, 21])
>>> x + y
array([19, 19, 19, 19, 19], dtype=uint8)

надо будет считать такие числа в огромных количествах (скажем 20 000 000)

this

Crocodoom ★★★★★
()
Последнее исправление: Crocodoom (всего исправлений: 1)
Ответ на: комментарий от yoghurt

Уже сделали, Crocodoom эксперт по Python выше правильно подсказал - есть np и его вектора - в нутрях оно вроде как нативное до предела.

I-Love-Microsoft ★★★★★
()

можно в питоне методом __eq__()

q13
()
Ответ на: комментарий от Octagon

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

SevikL ★★★★★
()
Ответ на: комментарий от Octagon

не исключено. я периодически что-то путаю. рассеянный я

SevikL ★★★★★
()

Для плюсов пользуемся свойствами машинной арифметики:

uint8_t v2()
{
  uint32_t a = 250;
  uint32_t b = 25;
  uint32_t c;
  for (size_t i = 0; i < 20000000; i++) {
    c = a + b;
    a = c;
  }
  return c & 0xff;
}

uint8_t v3()
{
  uint_fast8_t a = 250;
  uint_fast8_t b = 25;
  uint_fast8_t c;
  for (size_t i = 0; i < 20000000; i++) {
    c = a + b;
    a = c;
  }
  return c & 0xff;
}

для питона, переносим циклы внутрь numpy и используем свойства машинной арифметики:

import numpy as np

a = np.uint8(250)
b = np.full((20000000,), 25, dtype=np.uint8)
c = np.uint8(a + np.sum(b))
AlexVR ★★★★★
()
Ответ на: комментарий от peregrine

После тестирования алгоритма перепишу всё на C++, возможно даже с какой-нибудь cuda или OpenCL, чтобы это дело очень быстро работало.

Если цель - вычисления на gpu, то сразу пиши для gpu, тогда и проблемы из ОП не будет.

anonymous
()
Ответ на: комментарий от anonymous

Сейчас цель - прототипирование.

peregrine ★★★★★
() автор топика
Ответ на: комментарий от Octagon

Конечно победа, если цель писать код на питоне без попыток игнорировать написанные для него библиотеки. Сам питон (cpython) тоже не на питоне написан, насколько помню.

grem ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.