软件工程与应用第十一篇报告

本文继续深入分析RNS(剩余数系统)的代码实现,重点探讨了`decompose`和`compose`函数,这两个函数分别用于将数值转换为RNS表示和从RNS表示还原。通过对RNSbase的成员函数的解析,展示了如何利用剩余数系统提升计算效率。此外,还回顾了RNS的基本概念及其在算法加速中的应用。
摘要由CSDN通过智能技术生成

2021SC@SDUSC

2021-12-12

第十一周完成事项

工作内容

本周的工作是继续完成上周的rns剩余数系统的代码分析。首先还是让我们先了解一下剩余数系统。

RNS——剩余数系统

与冗余数相反,剩余数表示系统(RNS,residue number system)是一种用较少的数表示较多的数的表示系统。RNS可显著提高信号处理应用中某些算法密集型场景的算法速度。此外,RNS也是研究快速算法极限理论的一个工具。

RNS相关内容的补充

上星期在介绍rns的时候没有提到剩余数系统真正的内涵:用好几个小一点的数去表示大一点的数。

这样运算的时候就可以分别计算小一点的数来加快效率了,这就是为什么使用rns来表示原本数能加快运算速度的原因。

运用RNS进行加快运算举例

假如有一个数157,而我们的计算机居然只支持表示5比特的数(假如),也就是他uint类型的UINT_MAX为 2 5 − 1 = 31 2^5-1=31 251=31。那我们找到了这样两个互素的数17,23,那就可以将157表示为{4,19},其中4 = 157  mod   17 , 19 = 157   mod   23。
通过中国剩余定理,我们可以来恢复一下原数,已知:
{ 4 = x m o d 17 19 = x m o d 23 \begin{cases} 4 = x mod 17 \\ 19 = x mod 23 \end{cases} {4=xmod1719=xmod23
那么可以求x = 4 ∗ 23 ∗ 3 + 19 ∗ 17 ∗ 19 = 6413 ≡ 157 mod (17 ∗ 23 = 391)

其中19是17模23的逆元,3是23模17的逆元。

那假如我们要计算157 + 35 = 192 mod 391,以及21 = 157 ∗ 35 mod 391
那我们将35也进行RNS表达为{1,12},

5 = 1 + 4 mod 17, 8 = 19 + 12 mod 23
4 = 1 × 4 mod 17, 21 = 19 × 12 mod 23

我们分别对{5,8},{4,21}进行CRT恢复,神奇的事情发生啦,恢复的结果正好为192和21。

代码分析

承接上周的进度,上周讲到了对RNSbase模数的更改,这周将继续分析相关代码。

void decompose(std::uint64_t *value, MemoryPoolHandle pool) const;

void decompose_array(std::uint64_t *value, std::size_t count, MemoryPoolHandle pool) const;

void compose(std::uint64_t *value, MemoryPoolHandle pool) const;

void compose_array(std::uint64_t *value, std::size_t count, MemoryPoolHandle pool) const;

首先是数与RNS表示的转换,decompose函数是将原本的数分解为RNS表示的数,decompose_array函数是将一组数转化为RNS表示的数,compose与之相反。

这里主要讲解一下decompose和compose,对于decompose_array和compose_array来说,相当于decompose和compose的变体,与之类似,这里就不再过多陈述。


首先我们来看一下decompose函数的主要内容。

void RNSBase::decompose(uint64_t *value, MemoryPoolHandle pool) const
{
	if (!value)
    {
		throw invalid_argument("value cannot be null");
    }
    if (!pool)
    {
        throw invalid_argument("pool is uninitialized");
    }

    if (size_ > 1)
    {
        // Copy the value
        auto value_copy(allocate_uint(size_, pool));
        set_uint(value, size_, value_copy.get());

        SEAL_ITERATE(iter(value, base_), size_, [&](auto I) {
			get<0>(I) = modulo_uint(value_copy.get(), size_, get<1>(I));
        });
    }
}

decompose函数首先是对传进来的数进行判断,判断value值是否为空以及判断内存池句柄是否初始化,如果没有就弹出警告。

然后判断当前RNSbase的size是否大于1,如果是则进行复制和迭代操作。


然后是compose函数的主要内容。

void RNSBase::compose(uint64_t *value, MemoryPoolHandle pool) const
{
	if (!value)
    {
		throw invalid_argument("value cannot be null");
    }
    if (!pool)
    {
        throw invalid_argument("pool is uninitialized");
    }

    if (size_ > 1)
    {
        // Copy the value
        auto temp_value(allocate_uint(size_, pool));
        set_uint(value, size_, temp_value.get());

        // Clear the result
        set_zero_uint(size_, value);

        StrideIter<uint64_t *> punctured_prod(punctured_prod_array_.get(), size_);

        // Compose an array of integers (one per base element) into a single multi-precision integer
        auto temp_mpi(allocate_uint(size_, pool));
        SEAL_ITERATE(
			iter(temp_value, inv_punctured_prod_mod_base_array_, punctured_prod, base_), size_, [&](auto I) {
				uint64_t temp_prod = multiply_uint_mod(get<0>(I), get<1>(I), get<3>(I));
                multiply_uint(get<2>(I), size_, temp_prod, size_, temp_mpi.get());
                add_uint_uint_mod(temp_mpi.get(), value, base_prod_.get(), size_, value);
        });
    }
}

compose函数首先也是判断value值和pool值,然后判断RNSbase的size是否大于1。接下来的操作基本上大同小异,先根据value创建一个副本,然后根据迭代器,还原出数。


关于RNSbase最后的内容就是相关变量的获取,这里涉及到尚未分析的内容这里就不再过多的陈述。

SEAL_NODISCARD inline const Modulus *base() const noexcept
{
	return base_.get();
}

SEAL_NODISCARD inline const std::uint64_t *base_prod() const noexcept
{
	return base_prod_.get();
}

SEAL_NODISCARD inline const std::uint64_t *punctured_prod_array() const noexcept
{
	return punctured_prod_array_.get();
}

SEAL_NODISCARD inline const MultiplyUIntModOperand *inv_punctured_prod_mod_base_array() const noexcept
{
	return inv_punctured_prod_mod_base_array_.get();
}

至此关于RNSbase,也就是和剩余数系统的基本内容到这里就分析完成了。

从上周分析到现在,看到了RNSbase的构造函数、复制构造函数以及赋值构造函数,看到了判断包含和子集的函数,看到了添加和删除元素的函数,也看到了合成和分解的函数,到这里,整个RNS的内容完成了三分之一,接下来下周将对里面所包含的变量内容进行分析。

总结

这次首先是回顾了上星期分析的有关剩余数系统的相关内容,并沿着上星期的代码分析进度继续分析了剩余数系统的相关代码。

最后,感谢孔老师的指导,感谢戴老师和其他审核老师的阅读!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值