Исходный код NumPy может быть сложным для навигации, потому что он имеет так много функций для очень многих типов данных.Вы можете найти исходный код уровня C для функции абсолютного значения в файле scalarmath.c.src
.Этот файл на самом деле является шаблоном с определениями функций, которые впоследствии реплицируются системой сборки для нескольких типов данных.Обратите внимание, что каждая функция - это «ядро», которое запускается для каждого элемента массива (цикл в массиве выполняется где-то еще).Функции всегда называются <name of the type>_ctype_absolute
, где <name of the type>
- это тип данных, к которому он применяется, и обычно является шаблонным.Давайте рассмотрим их.
/**begin repeat
* #name = ubyte, ushort, uint, ulong, ulonglong#
*/
#define @name@_ctype_absolute @name@_ctype_positive
/**end repeat**/
Это для неподписанных типов.В этом случае абсолютное значение совпадает с np.positive
, которое просто копирует значение без каких-либо действий (это то, что вы получаете, если у вас есть массив a
и вы делаете +a
).
/**begin repeat
* #name = byte, short, int, long, longlong#
* #type = npy_byte, npy_short, npy_int, npy_long, npy_longlong#
*/
static void
@name@_ctype_absolute(@type@ a, @type@ *out)
{
*out = (a < 0 ? -a : a);
}
/**end repeat**/
Это для целых чисел со знаком.Довольно просто.
/**begin repeat
* #name = float, double, longdouble#
* #type = npy_float, npy_double, npy_longdouble#
* #c = f,,l#
*/
static void
@name@_ctype_absolute(@type@ a, @type@ *out)
{
*out = npy_fabs@c@(a);
}
/**end repeat**/
Это для значений с плавающей запятой.Здесь используются функции npy_fabsf
, npy_fabs
и npy_fabsl
.Они объявлены в npy_math.h
, но определены с помощью шаблонного кода C в npy_math_internal.h.src
, по сути, вызывая аналоги C / C99 (если C99 не доступен, , в этом случае fabsf
и fabsl
эмулируются с fabs
).Вы можете подумать, что предыдущий код должен работать также для типов с плавающей запятой, но на самом деле они более сложные, поскольку в них есть такие вещи, как NaN, бесконечность или знаковые нули, поэтому лучше использовать стандартные функции C, которые имеют дело со всемнадежно.
static void
half_ctype_absolute(npy_half a, npy_half *out)
{
*out = a&0x7fffu;
}
На самом деле это не шаблон, это функция абсолютного значения для значений с плавающей точкой с половинной точностью .Оказывается, вы можете изменить знак, просто выполнив эту побитовую операцию (установите первый бит равным 0), поскольку половинная точность проще (если более ограничена), чем другие типы с плавающей запятой (обычно это то же самое для тех, но в особых случаях).
/**begin repeat
* #name = cfloat, cdouble, clongdouble#
* #type = npy_cfloat, npy_cdouble, npy_clongdouble#
* #rtype = npy_float, npy_double, npy_longdouble#
* #c = f,,l#
*/
static void
@name@_ctype_absolute(@type@ a, @rtype@ *out)
{
*out = npy_cabs@c@(a);
}
/**end repeat**/
Последний предназначен для сложных типов.Они используют функции npy_cabsf
, npycabs
и npy_cabsl
, снова объявленные в npy_math.h
, но в этом случае реализованные в шаблонах в npy_math_complex.c.src
с использованием функций C99 (если это не доступно, в этом случае эмулируется с np.hypot
).