Основная математическая библиотека NumPy#

Эта библиотека содержит большую часть математической функциональности C99, которую можно использовать на платформах, где C99 плохо поддерживается. Основные математические функции имеют тот же API, что и C99, за исключением npy_* префикс.

Доступные функции определены в - пожалуйста, обратитесь к этому заголовку, если есть сомнения.

Примечание

Ведётся работа по обеспечению npymath меньше (поскольку совместимость с C99 компиляторов улучшилась со временем) и более удобна для распространения или использования в качестве зависимости только с заголовочными файлами. Это позволит избежать проблем с поставкой статической библиотеки, собранной компилятором, который может не совпадать с компилятором, используемым нижестоящим пакетом или конечным пользователем. См. gh-20880 подробности.

Классификация чисел с плавающей запятой#

NPY_NAN#

Этот макрос определен как NaN (не число) и гарантированно имеет не установленный знаковый бит ('положительный' NaN). Соответствующие макросы одинарной и расширенной точности доступны с суффиксами F и L.

NPY_INFINITY#

Этот макрос определён как положительная бесконечность. Соответствующие макросы для одинарной и расширенной точности доступны с суффиксами F и L.

NPY_PZERO#

Этот макрос определен как положительный ноль. Соответствующие макросы для одинарной и расширенной точности доступны с суффиксами F и L.

NPY_NZERO#

Этот макрос определён как отрицательный ноль (то есть с установленным битом знака). Соответствующие макросы для одинарной и расширенной точности доступны с суффиксами F и L.

npy_isnan(x)#

Это псевдоним для C99 isnan: работает для одинарной, двойной и расширенной точности и возвращает ненулевое значение, если x является NaN.

npy_isfinite(x)#

Это псевдоним для C99 isfinite: работает для одинарной, двойной и расширенной точности и возвращает ненулевое значение, если x не является NaN и не бесконечностью.

npy_isinf(x)#

Это псевдоним для C99 isinf: работает для одинарной, двойной и расширенной точности, возвращает ненулевое значение, если x бесконечен (положительный или отрицательный).

npy_signbit(x)#

Это псевдоним для C99 signbit: работает для одинарной, двойной и расширенной точности и возвращает ненулевое значение, если у x установлен знаковый бит (то есть число отрицательное).

npy_copysign(x, y)#

Это псевдоним для C99 copysign: возвращает x с тем же знаком, что и y. Работает для любых значений, включая inf и nan. Одинарная и расширенная точность доступны с суффиксами f и l.

Полезные математические константы#

Следующие математические константы доступны в npy_math.h. Одинарная и расширенная точность также доступны путем добавления f и l суффиксы соответственно.

NPY_E#

Основание натурального логарифма (\(e\))

NPY_LOG2E#

Логарифм по основанию 2 от постоянной Эйлера (\(\frac{\ln(e)}{\ln(2)}\))

NPY_LOG10E#

Логарифм по основанию 10 от постоянной Эйлера (\(\frac{\ln(e)}{\ln(10)}\))

NPY_LOGE2#

Натуральный логарифм 2 (\(\ln(2)\))

NPY_LOGE10#

Натуральный логарифм 10 (\(\ln(10)\))

NPY_PI#

Пи (\(\pi\))

NPY_PI_2#

Пи, делённое на 2 (\(\frac{\pi}{2}\))

NPY_PI_4#

Пи, делённое на 4 (\(\frac{\pi}{4}\))

NPY_1_PI#

Обратное значение числа пи (\(\frac{1}{\pi}\))

NPY_2_PI#

Дважды обратное значение числа пи (\(\frac{2}{\pi}\))

NPY_EULER#
Константа Эйлера

\(\lim_{n\rightarrow\infty}({\sum_{k=1}^n{\frac{1}{k}}-\ln n})\)

Низкоуровневая манипуляция с плавающей точкой#

Они могут быть полезны для точного сравнения чисел с плавающей запятой.

double npy_nextafter(double x, double y)#

Это алиас для C99 nextafter: возвращает следующее представимое значение с плавающей точкой от x в направлении y. Одинарная и расширенная точность доступны с суффиксами f и l.

double npy_spacing(double x)#

Это функция, эквивалентная встроенной функции Fortran. Возвращает расстояние между x и следующим представимым значением с плавающей запятой от x, например spacing(1) == eps. spacing для nan и +/- inf возвращает nan. Одинарная и расширенная точности доступны с суффиксами f и l.

void npy_set_floatstatus_divbyzero()#

Установить исключение деления на ноль с плавающей точкой

void npy_set_floatstatus_overflow()#

Указывает, должны ли предупреждения перехватываться пользовательной реализацией

void npy_set_floatstatus_underflow()#

Установить исключение потери значимости для чисел с плавающей точкой

void npy_set_floatstatus_invalid()#

Установить исключение недопустимой операции с плавающей запятой

int npy_get_floatstatus()#

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

  • NPY_FPE_DIVIDEBYZERO

  • NPY_FPE_OVERFLOW

  • NPY_FPE_UNDERFLOW

  • NPY_FPE_INVALID

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

int npy_get_floatstatus_barrier(char*)#

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

Возвращает битовую маску со следующими возможными флагами:

  • NPY_FPE_DIVIDEBYZERO

  • NPY_FPE_OVERFLOW

  • NPY_FPE_UNDERFLOW

  • NPY_FPE_INVALID

int npy_clear_floatstatus()#

Очищает статус чисел с плавающей запятой. Возвращает предыдущую маску статуса.

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

int npy_clear_floatstatus_barrier(char*)#

Очищает статус чисел с плавающей запятой. Указатель на локальную переменную передаётся для предотвращения агрессивных оптимизаций компилятора, которые могут переупорядочить этот вызов функции. Возвращает предыдущую маску статуса.

Поддержка комплексных чисел#

Были добавлены функции комплексных чисел, подобные C99. Их можно использовать, если вы хотите реализовать переносимые расширения на C. Начиная с NumPy 2.0 мы используем типы комплексных чисел C99 в качестве базового типа:

typedef double _Complex npy_cdouble;
typedef float _Complex npy_cfloat;
typedef long double _Complex npy_clongdouble;

MSVC не поддерживает _Complex сам тип, но добавил поддержку C99 complex.h заголовок, предоставляя собственную реализацию. Таким образом, под MSVC будут использоваться эквивалентные типы MSVC:

typedef _Dcomplex npy_cdouble;
typedef _Fcomplex npy_cfloat;
typedef _Lcomplex npy_clongdouble;

Поскольку MSVC всё ещё не поддерживает синтаксис C99 для инициализации комплексного числа, вам нужно ограничиться синтаксисом, совместимым с C90, например:

/* a = 1 + 2i \*/
npy_complex a = npy_cpack(1, 2);
npy_complex b;

b = npy_log(a);

Несколько утилит также добавлены в numpy/npy_math.h, чтобы получить или установить действительную или мнимую часть комплексного числа:

npy_cdouble c;
npy_csetreal(&c, 1.0);
npy_csetimag(&c, 0.0);
printf("%d + %di\n", npy_creal(c), npy_cimag(c));

Изменено в версии 2.0.0: Базовые C-типы для всех комплексных типов numpy были изменены на использование C99 комплексных типов. До сих пор для представления комплексных типов использовалось следующее:

typedef struct { double real, imag; } npy_cdouble;
typedef struct { float real, imag; } npy_cfloat;
typedef struct {npy_longdouble real, imag;} npy_clongdouble;

Используя struct представление гарантировало, что комплексные числа могут использоваться на всех платформах, даже на тех, которые не поддерживают встроенные типы комплексных чисел. Это также означало, что статическая библиотека должна была поставляться вместе с NumPy, чтобы обеспечить слой совместимости C99 для использования в сторонних пакетах. Однако в последние годы поддержка нативных типов комплексных чисел значительно улучшилась, с добавлением в MSVC встроенной поддержки для complex.h заголовок в 2019 году.

Для упрощения совместимости между версиями были добавлены макросы, использующие новые API наборов.

#define NPY_CSETREAL(z, r) npy_csetreal(z, r)
#define NPY_CSETIMAG(z, i) npy_csetimag(z, i)

Слой совместимости также предоставляется в numpy/npy_2_complexcompat.h. Он проверяет, существуют ли макросы, и возвращается к синтаксису 1.x, если они не существуют.

#include 

#ifndef NPY_CSETREALF
#define NPY_CSETREALF(c, r) (c)->real = (r)
#endif
#ifndef NPY_CSETIMAGF
#define NPY_CSETIMAGF(c, i) (c)->imag = (i)
#endif

Мы предлагаем всем зависимым пакетам, которым нужна эта функциональность, скопировать код слоя совместимости в свои исходники и использовать его, чтобы они могли продолжать поддерживать как NumPy 1.x, так и 2.x без проблем. Также обратите внимание, что complex.h заголовок включён в numpy/npy_common.h, что делает complex зарезервированное ключевое слово.

Связывание с основной математической библиотекой в расширении#

Чтобы использовать основную математическую библиотеку, которую NumPy поставляет как статическую библиотеку в вашем собственном расширении Python, вам нужно добавить npymath параметры компиляции и компоновки для вашего расширения. Конкретные шаги будут зависеть от используемой системы сборки. Общие шаги:

  1. Добавьте каталог включений numpy (= значение np.get_include()) в ваши каталоги include,

  2. The npymath статическая библиотека находится в lib каталог непосредственно рядом с каталогом include numpy (т.е., pathlib.Path(np.get_include()) / '..' / 'lib'). Добавьте это в ваши каталоги поиска библиотек,

  3. Связать с libnpymath и libm.

Примечание

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

При сборке с numpy.distutils (устаревший), затем используйте это в вашем setup.py:

>>> from numpy.distutils.misc_util import get_info
>>> info = get_info('npymath')
>>> _ = config.add_extension('foo', sources=['foo.c'], extra_info=info)

Другими словами, использование info точно такой же, как при использовании blas_info и др.

Когда вы собираете с Meson, используйте:

# Note that this will get easier in the future, when Meson has
# support for numpy built in; most of this can then be replaced
# by `dependency('numpy')`.
incdir_numpy = run_command(py3,
  [
    '-c',
    'import os; os.chdir(".."); import numpy; print(numpy.get_include())'
  ],
  check: true
).stdout().strip()

inc_np = include_directories(incdir_numpy)

cc = meson.get_compiler('c')
npymath_path = incdir_numpy / '..' / 'lib'
npymath_lib = cc.find_library('npymath', dirs: npymath_path)

py3.extension_module('module_name',
  ...
  include_directories: inc_np,
  dependencies: [npymath_lib],

Функции половинной точности#

Заголовочный файл предоставляет функции для работы с 16-битными значениями с плавающей запятой IEEE 754-2008. Хотя этот формат обычно не используется для численных вычислений, он полезен для хранения значений, требующих плавающей запятой, но не нуждающихся в высокой точности. Также может использоваться как учебный инструмент для понимания природы ошибок округления с плавающей запятой.

Как и для других типов, NumPy включает typedef npy_half для 16-битного числа с плавающей точкой. В отличие от большинства других типов, вы не можете использовать его как обычный тип в C, поскольку это typedef для npy_uint16. Например, 1.0 выглядит как 0x3c00 для C, и если вы выполните сравнение на равенство между различными знаковыми нулями, вы получите -0.0 != 0.0 (0x8000 != 0x0000), что неверно.

По этим причинам NumPy предоставляет API для работы со значениями npy_half, доступный при включении и ссылка на npymath. Для функций, которые не предоставляются напрямую, таких как арифметические операции, предпочтительным методом является преобразование в float или double и обратно, как в следующем примере.

npy_half sum(int n, npy_half *array) {
    float ret = 0;
    while(n--) {
        ret += npy_half_to_float(*array++);
    }
    return npy_float_to_half(ret);
}

Внешние ссылки:

NPY_HALF_ZERO#

Этот макрос определен как положительный ноль.

NPY_HALF_PZERO#

Этот макрос определен как положительный ноль.

NPY_HALF_NZERO#

Этот макрос определен как отрицательный ноль.

NPY_HALF_ONE#

Этот макрос определен как 1.0.

NPY_HALF_NEGONE#

Этот макрос определен как -1.0.

NPY_HALF_PINF#

Этот макрос определён как +inf.

NPY_HALF_NINF#

Этот макрос определен как -inf.

NPY_HALF_NAN#

Этот макрос определён как значение NaN, гарантированно с неустановленным битом знака.

float npy_half_to_float(npy_half h)#

Преобразует число с половинной точностью в число с одинарной точностью.

double npy_half_to_double(npy_half h)#

Преобразует число с половинной точностью в число с двойной точностью.

npy_half npy_float_to_half(float f)#

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

npy_half npy_double_to_half(double d)#

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

int npy_half_eq(npy_half h1, npy_half h2)#

Сравнивает два числа с половинной точностью (h1 == h2).

int npy_half_ne(npy_half h1, npy_half h2)#

Сравнивает два числа с половинной точностью (h1 != h2).

int npy_half_le(npy_half h1, npy_half h2)#

Сравнивает два числа с половинной точностью (h1 <= h2).

int npy_half_lt(npy_half h1, npy_half h2)#

Сравнивает два числа с половинной точностью (h1 < h2).

int npy_half_ge(npy_half h1, npy_half h2)#

Сравнивает два числа с половинной точностью (h1 >= h2).

int npy_half_gt(npy_half h1, npy_half h2)#

Сравнивает два числа с плавающей точкой половинной точности (h1 > h2).

int npy_half_eq_nonan(npy_half h1, npy_half h2)#

Сравнивает два числа с половинной точностью, которые, как известно, не являются NaN (h1 == h2). Если значение NaN, результат не определен.

int npy_half_lt_nonan(npy_half h1, npy_half h2)#

Сравнивает два числа с половинной точностью, которые точно не являются NaN (h1 < h2). Если значение NaN, результат не определён.

int npy_half_le_nonan(npy_half h1, npy_half h2)#

Сравнивает два числа с половинной точностью, которые точно не являются NaN (h1 <= h2). Если значение NaN, результат не определен.

int npy_half_iszero(npy_half h)#

Проверяет, имеет ли число с половинной точностью значение, равное нулю. Это может быть немного быстрее, чем вызов npy_half_eq(h, NPY_ZERO).

int npy_half_isnan(npy_half h)#

Проверяет, является ли число половинной точности NaN.

int npy_half_isinf(npy_half h)#

Проверяет, является ли число с половинной точностью плюс или минус бесконечностью.

int npy_half_isfinite(npy_half h)#

Проверяет, является ли половинная точность с плавающей запятой конечной (не NaN или Inf).

int npy_half_signbit(npy_half h)#

Возвращает 1, если h отрицательно, 0 в противном случае.

npy_half npy_half_copysign(npy_half x, npy_half y)#

Возвращает значение x со скопированным битом знака из y. Работает для любого значения, включая Inf и NaN.

npy_half npy_half_spacing(npy_half h)#

То же самое для половинной точности float, как npy_spacing и npy_spacingf, описанные в разделе низкоуровневых операций с плавающей точкой.

npy_half npy_half_nextafter(npy_half x, npy_half y)#

Это то же самое для половинной точности с плавающей точкой, что и npy_nextafter и npy_nextafterf, описанные в разделе низкоуровневых операций с плавающей точкой.

npy_uint16 npy_floatbits_to_halfbits(npy_uint32 f)#

Низкоуровневая функция, которая преобразует 32-битное число с плавающей точкой одинарной точности, хранящееся как uint32, в 16-битное число с плавающей точкой половинной точности.

npy_uint16 npy_doublebits_to_halfbits(npy_uint64 d)#

Низкоуровневая функция, которая преобразует 64-битное число двойной точности с плавающей запятой, хранящееся как uint64, в 16-битное число половинной точности с плавающей запятой.

npy_uint32 npy_halfbits_to_floatbits(npy_uint16 h)#

Низкоуровневая функция, которая преобразует 16-битное число с плавающей запятой половинной точности в 32-битное число с плавающей запятой одинарной точности, хранящееся как uint32.

npy_uint64 npy_halfbits_to_doublebits(npy_uint16 h)#

Низкоуровневая функция, которая преобразует 16-битное число половинной точности в 64-битное число двойной точности, хранящееся как uint64.