MicroPython 是一种适用于微控制器和其他受限环境的 Python 编程语言的实现。它旨在提供与 Python 3 语言的紧密兼容,同时考虑到内存和计算资源的限制。MicroPython 库是这门语言的核心组成部分,提供了一系列的模块和函数,使得开发者能够在硬件上执行各种任务。
下面将通过系列文章,逐一解读microPython,以便让读者了解掌握microPython的整个核心逻辑.,以便读者可以透过这个Python的最小内核,掌握Python解析器的核心实现逻辑,学习世界上最优秀的源码设计之一.
以上代码实现了多种数学运算,包括位运算、乘法、除法、取模、幂运算等,以及将大整数转换为字节序列和字符串的功能。
#include <string.h>
#include <assert.h>
// 引入大整数库的头文件
#include "py/mpz.h"
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
// 定义数字的大小和掩码等常量
#define DIG_SIZE (MPZ_DIG_SIZE) // 每个数字的大小
#define DIG_MASK ((MPZ_LONG_1 << DIG_SIZE) - 1) // 单个数字的掩码
#define DIG_MSB (MPZ_LONG_1 << (DIG_SIZE - 1)) // 最高位掩码
#define DIG_BASE (MPZ_LONG_1 << DIG_SIZE) // 进制基数
/*
mpz 是一个任意精度整数类型,具有公共 API。
mpn 函数对非负整数进行操作,这些整数由一系列广义数字表示(例如,每个数字一个字)。
您还需要单独指定数组的长度。
没有公开的 mpn API。相反,这些函数被 mpz 用来实现其功能。
整数值以小端格式存储(第一个数字在内存中最先)。
规范化的定义是什么?
*/
// 移除数字数组尾部的零
static size_t mpn_remove_trailing_zeros(mpz_dig_t *oidig, mpz_dig_t *idig) {
for (--idig; idig >= oidig && *idig == 0; --idig) {
}
return idig + 1 - oidig;
}
// 比较 i 和 j
// 返回 i - j 的符号
// 假设 i 和 j 已经规范化
static int mpn_cmp(const mpz_dig_t *idig, size_t ilen, const mpz_dig_t *jdig, size_t jlen) {
if (ilen < jlen) {
return -1;
}
if (ilen > jlen) {
return 1;
}
for (idig += ilen, jdig += ilen; ilen > 0; --ilen) {
mpz_dbl_dig_signed_t cmp = (mpz_dbl_dig_t)*(--idig) - (mpz_dbl_dig_t)*(--jdig);
if (cmp < 0) {
return -1;
}
if (cmp > 0) {
return 1;
}
}
return 0;
}
// 计算 i = j << n
// 返回 i 中的数字个数
// 假设 i 的内存足够;假设 j 已经规范化;假设 n > 0
// 可以有 i 和 j 指向相同的内存
static size_t mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mp_uint_t n) {
// 计算 n 需要移动的位数和部分位数
mp_uint_t n_whole = (n + DIG_SIZE - 1) / DIG_SIZE;
mp_uint_t n_part = n % DIG_SIZE;
if (n_part == 0) {
n_part = DIG_SIZE;
}
// 从高位开始移动数字
idig += jlen + n_whole - 1;
jdig += jlen - 1;
// 进行位移
mpz_dbl_dig_t d = 0;
for (size_t i = jlen; i > 0; i--, idig--, jdig--) {
d |= *jdig;
*idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
d <<= DIG_SIZE;
}
// 存储剩余的位
*idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
idig -= n_whole - 1;
memset(idig, 0, (n_whole - 1) * sizeof(mpz_dig_t));
// 计算结果的长度
jlen += n_whole;
while (jlen != 0 && idig[jlen - 1] == 0) {
jlen--;
}
// 返回结果的长度
return jlen;
}
// 计算 i = j >> n
// 返回 i 中的数字个数
// 假设 i 的内存足够;假设 j 已经规范化;假设 n > 0
// 可以有 i 和 j 指向相同的内存
static size_t mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mp_uint_t n) {
mp_uint_t n_whole = n / DIG_SIZE;
mp_uint_t n_part = n % DIG_SIZE;
if (n_whole >= jlen) {
return 0;
}
jdig += n_whole;
jlen -= n_whole;
for (size_t i = jlen; i > 0; i--, idig++, jdig++) {
mpz_dbl_dig_t d = *jdig;
if (i > 1) {
d |= (mpz_dbl_dig_t)jdig[1] << DIG_SIZE;
}
d >>= n_part;
*idig = d & DIG_MASK;
}
if (idig[-1] == 0) {
jlen--;
}
return jlen;
}
// 计算 i = j + k
// 返回 i 中的数字个数
// 假设 i 的内存足够;假设 j 和 k 已经规范化;假设 jlen >= klen
// 可以有 i, j, k 指向相同的内存
static size_t mpn_add(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) {
mpz_dig_t *oidig = idig;
mpz_dbl_dig_t carry = 0;
jlen -= klen;
for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
carry += (mpz_dbl_dig_t)*jdig + (mpz_dbl_dig_t)*kdig;
*idig = carry & DIG_MASK;
carry >>= DIG_SIZE;
}
for (; jlen > 0; --jlen, ++idig, ++jdig) {
carry += *jdig;
*idig = carry & DIG_MASK;
carry >>= DIG_SIZE;
}
if (carry != 0) {
*idig++ = carry;
}
return idig - oidig;
}
// 计算 i = j - k
// 返回 i 中的数字个数
// 假设 i 的内存足够;假设 j 和 k 已经规范化;假设 j >= k
// 可以有 i, j, k 指向相同的内存
static size_t mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) {
mpz_dig_t *oidig = idig;
mpz_dbl_dig_signed_t borrow = 0;
jlen -= klen;
for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
borrow += (mpz_dbl_dig_t)*jdig - (mpz_dbl_dig_t)*kdig;
*idig = borrow & DIG_MASK;
borrow >>= DIG_SIZE;
}
for (; jlen > 0; --jlen, ++idig, ++jdig) {
borrow += *jdig;
*idig = borrow & DIG_MASK;
borrow >>= DIG_SIZE;
}
return mpn_remove_trailing_zeros(oidig, idig);
}
// 以下代码块在 MICROPY_OPT_MPZ_BITWISE 被定义时才会编译
#if MICROPY_OPT_MPZ_BITWISE
// 计算 i = j & k
// 返回 i 中的数字个数
// 假设 i 的内存足够;假设 j 和 k 已经规范化;假设 jlen >= klen (jlen 参数实际上不需要)
// 可以有 i, j, k 指向相同的内存
static size_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, const mpz_dig_t *kdig, size_t klen) {
mpz_dig_t *oidig = idig;
for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
*idig = *jdig & *kdig;
}
return mpn_remove_trailing_zeros(oidig, idig);
}
#endif
// 计算 i = -((-j) & (-k)) = ~((~j + 1) & (~k + 1)) + 1
// i = (j & (-k)) = (j & (~k + 1)) = (j & (~k + 1))
// i = (-j) & k) = ((~j + 1) & k) = ((~j + 1)& k)
// 计算通用形式:
// i = (im ^ (((j ^ jm) + jc) & ((k ^ km) + kc))) + ic where Xm = Xc == 0 ? 0 : DIG_MASK
// 返回 i 中的数字个数
// 假设 i 的内存足够;假设 j 和 k 已经规范化;假设 jlen >= klen
// 可以有 i, j, k 指向相同的内存
static size_t mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
mpz_dig_t *oidig = idig;
mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK;
mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;
for (; jlen > 0; ++idig, ++jdig) {
carryj += *jdig ^ jmask;
carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;
carryi += ((carryj & carryk) ^ imask) & DIG_MASK;
*idig = carryi & DIG_MASK;
carryk >>= DIG_SIZE;
carryj >>= DIG_SIZE;
carryi >>= DIG_SIZE;
}
if (0 != carryi) {
*idig++ = carryi;
}
return mpn_remove_trailing_zeros(oidig, idig);
}
#if MICROPY_OPT_MPZ_BITWISE
// 计算 i = -((-j) | (-k)) = ~((~j + 1) | (~k + 1)) + 1
// i = -(j | (-k)) = -(j | (~k + 1)) = ~(j | (~k + 1)) + 1
// i = -((-j) | k) = -((~j + 1) | k) = ~((~j + 1) | k) + 1
// 计算通用形式:
// i = ~(((j ^ jm) + jc) | ((k ^ km) + kc)) + 1 where Xm = Xc == 0 ? 0 : DIG_MASK
// 返回 i 中的数字个数
// 假设 i 的内存足够;假设 j 和 k 已经规范化;假设 jlen >= klen
// 可以有 i, j, k 指向相同的内存
static size_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
mpz_dig_t *oidig = idig;
mpz_dbl_dig_t carryi = 1;
mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;
for (; jlen > 0; ++idig, ++jdig) {
carryj += *jdig ^ jmask;
carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;
carryi += ((carryj | carryk) ^ DIG_MASK) & DIG_MASK;
*idig = carryi & DIG_MASK;
carryk >>= DIG_SIZE;
carryj >>= DIG_SIZE;
carryi >>= DIG_SIZE;
}
// 至少 j 或 k 之一必须是非零的,所以上面的循环至少运行一次。
// 如果 carryi 在这里不为零,它必须在每次循环迭代结束时都为零。
// 因此,carryi 必须每次都溢出,即 carryi += 0xff..ff。
// 所以 carryj|carryk 必须在每次迭代中在 DIG_MASK 位上为零。
// 但考虑到 j,k 所有可能的符号情况,这是不可能的。
assert(carryi == 0);
return mpn_remove_trailing_zeros(oidig, idig);
}
#else
// 计算 i = -((-j) | (-k)) = ~((~j + 1) | (~k + 1)) + 1
// i = -(j | (-k)) = -(j | (~k + 1)) = ~(j | (~k + 1)) + 1
// i = -((-j) | k) = -((~j + 1) | k) = ~((~j + 1) | k) + 1
// 计算通用形式:
// i = ~(((j ^ jm) + jc) | ((k ^ km) + kc)) + 1 where Xm = Xc == 0 ? 0 : DIG_MASK
// 返回 i 中的数字个数
// 假设 i 的内存足够;假设 j 和 k 已经规范化;假设 jlen >= klen
// 可以有 i, j, k 指向相同的内存
static size_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
mpz_dig_t *oidig = idig;
mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK;
mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;
for (; jlen > 0; ++idig, ++jdig) {
carryj += *jdig ^ jmask;
carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;
carryi += ((carryj | carryk) ^ imask) & DIG_MASK;
*idig = carryi & DIG_MASK;
carryk >>= DIG_SIZE;
carryj >>= DIG_SIZE;
carryi >>= DIG_SIZE;
}
// 参见上面 mpn_or_neg 的注释,为什么 carryi 必须为零。
assert(carryi == 0);
return mpn_remove_trailing_zeros(oidig, idig);
}
#endif
#if MICROPY_OPT_MPZ_BITWISE
// 计算 i = j ^ k
// 返回 i 中的数字个数
// 假设 i 的内存足够;假设 j 和 k 已经规范化;假设 jlen >= klen
// 可以有 i, j, k 指向相同的内存
static size_t mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) {
mpz_dig_t *oidig = idig;
jlen -= klen;
for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
*idig = *jdig ^ *kdig;
}
for (; jlen > 0; --jlen, ++idig, ++jdig) {
*idig = *jdig;
}
return mpn_remove_trailing_zeros(oidig, idig);
}
#endif
// 计算 i = (-j) ^ (-k) = ~(j - 1) ^ ~(k - 1) = (j - 1) ^ (k - 1)
// i = -(j ^ (-k)) = -(j ^ ~(k - 1)) = ~(j ^ ~(k - 1)) + 1 = (j ^ (k - 1)) + 1
// i = -((-j) ^ k) = -(~(j - 1) ^ k) = ~(~(j - 1) ^ k) + 1 = ((j - 1) ^ k) + 1
// 计算通用形式:
// i = ((j - 1 + jc) ^ (k - 1 + kc)) + ic
// 返回 i 中的数字个数
// 假设 i 的内存足够;假设 j 和 k 已经规范化;假设 jlen >= klen
// 可以有 i, j, k 指向相同的内存
static size_t mpn_xor_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk){
mpz_dig_t *oidig = idig;
for (; jlen > 0; ++idig, ++jdig) {
carryj += *jdig + DIG_MASK;
carryk += (--klen <= --jlen) ? (*kdig++ + DIG_MASK) : DIG_MASK;
carryi += (carryj ^ carryk) & DIG_MASK;
*idig = carryi & DIG_MASK;
carryk >>= DIG_SIZE;
carryj >>= DIG_SIZE;
carryi >>= DIG_SIZE;
}
if (0 != carryi) {
*idig++ = carryi;
}
return