在裸机c中使用多精度

问题描述 投票:3回答:2

所以我有一个树莓派零,然后我跟随this真的很酷的教程,开始用裸机c编程。一切都很好。

现在,我需要256或512位大小的(无符号)整数,因此我开始寻找库。我找到了BigDigits,并使其在我的机器上可以轻松工作。

尽管,当我尝试使用其余的实际裸机代码进行编译时(即使不包含它,也没有在代码中的任何地方使用它,它都进行了编译和链接,而没有警告或错误,但是我的代码不再起作用,即树莓派没有像以前那样做。

我对裸机编程还是很陌生。我知道该库可能使用了尚未实现的系统功能,因此可能无法正常工作。但是我什至没有调用任何BigDigits函数,也没有包括它们的任何标头。

为什么它编译和链接但不起作用?以及如何使它工作,或者还有其他更容易在裸机c环境中使用的其他选项,以实现任意精度?我实际上总是在编译时就知道我需要什么精度,所以我很高兴拥有uint256_t类型或类似的东西,但是我找不到类似的东西。

提前感谢!

c raspberry-pi bare-metal arbitrary-precision
2个回答
0
投票

没有魔术,使用您的小学数学。

  1234
+ 5678
========

完成

  011
  1234
+ 5678
========
  6912

现在我们被教导了,但是没有意识到我们可以将其分解为多个部分

 110  
  34
+ 78
========
  12

将进位留在这里,并从lsnumber了解进位为零。

现在我们可以用前半部分的进位来完成另一半的问题。

  01
  12
+ 56
======
  69

合并结果得到6912。

这等效于第一个加法,而adc(带进位加法)则根据需要增加更多,因此您可以选择使用do加法来存储尽可能多的内存或寄存器。如果处理器没有带进位的加法器,但考虑到这里发生的情况,您仍然可以将其合成。每列都有一个进位和一个进位,例如有32位寄存器,但是在体系结构中没有进位或没有进位标志,您可以使用32位寄存器和位的低16位一次完成所有16位数学运算将您添加到下一个16位操作中将执行17。

计算机中的减法是求反,然后将您所使用的加法与反第二个操作数(一个补码)相加,然后将进位求反。或者您可能有一个减法指令和一个带借位的减法用于级联。

乘除法是可行的,但还有很多工作要做。从小学数学开始,也许使用二进制而不是十进制对列进行划分,就好像您完成数学并看到如何级联的方法一样,可以存储的位数是固定的位数。乘法只是移位和加法,对于二进制乘法则要容易得多,因为它既可以加整,也可以加零。有符号与无符号之和与加法无关,因为我们使用二进制补码表示有符号。但如果结果是输入位数的2倍,则乘法很重要(32位* 32位= 64位符号很重要32位* 32位= 32位,符号无关紧要)。对于划分,基于符号扩展同样重要。

知道了这一点,您现在也许可以找到一个库或从库中提取您需要丢弃的所有C库或与系统调用相关的内容。

现在您正在使用C语言而不是汇编语言,因此您当然也可以在C语言中完成所有这些操作,可能还必须在较小的部分中完成它,例如使用32位变量并一次执行16位所有操作。一个32位一次添加16。

a = b + c

rb = b&0xFFFF;
rc = c&0xFFFF;
rd = rb+rc;
re = (b>>16)&0xFFFF; //being generic dont necessarily need the mask.
rf = (c>>16)&0xFFFF; //
rg = re+rf;
rg = rg+((rd>>16)&0xFFFF);
rd = rd & 0xFFFF;
rg = rg & 0xFFFF; //likely not necessary.
a = (rg<<16) | rd; //can use add or or here.

本可以使用rg的第17位,并根据需要继续进行级联。

您的较大变量可以是较小变量的数组,一个128位变量可以是无符号int x [4];

如果您使用两位数进行小学数学运算。

23是2 * 10 + 3 * 1或2 *(以幂1为底)加3 *(以幂0为底)

ab * cd,其中a,b,c,d是32位变量,但a是64位值的高32位,b是低32位,c高,d低。

我们的功效只有两个底数,因此可以表示为

(ax + by) * (cx + dy) = acxx + adxy + bcxy + bdyy

首先,外在,内在,持久地记住,还记得吗?

让您继续进行下去,但是您可以开始看到它以32位乘法结束,您可以使用32位系统执行此操作并进行一些移位,但是您实际上并没有执行这些移位如果您想要128位= 64位* 64位,但是如果您想要64位= 64位* 64位,则较大的寄存器将结果放入四个内存位置,或者将结果放入四个寄存器,而acxx变量随即消失,即x是1 << 32,所以x x是1 << 64。虽然a

d是32位* 32位= 64位结果,但如果您将自己限制为32位大小的变量(假设我没有64位变量类型),则在C中没有该结果例如,要使用较小的东西进行合成),您将再次需要一次执行16位操作。因为如果您将两个32位变量的上半部分清零,则等于16位* 16位= 32位

将要开始使用32位变量来合成64位数学运算,因为您确实有64位变量类型,可以通过随机或其他方式馈​​入代码测试向量并与使用全尺寸的编译输出进行比较,从而以编程方式对其进行测试。例如0x12345678aabbccdd * 0x456789abccddeeff以16位为单位使用32位变量(通过您的乘法函数使用)或作为两个64位变量(使用C编译器)并比较结果,并使用更多的测试向量进行重复。

同样,您可能会在其中一个库中找到实际的操作,然后将其剔除,并在其周围扔掉那些会干扰裸机的多余东西,一旦您考虑了他们如何做到这一点,然后查看他们的代码实际上在做什么。


-1
投票

像bignum库之类的东西可以用汇编编写,因为汇编不限于特定的数据类型,例如long, ...,也可以包含在C中作为外部/链接的(或可能是内部的)汇编代码,例如Assembly big numbers calculatorhttp://x86asm.net/articles/working-with-big-numbers-using-x86-instructions/。这必须移植到ARM组件(https://azeria-labs.com/arm-data-types-and-registers-part-2/)。包含到C中的是https://www.devdungeon.com/content/how-mix-c-and-assemblyhttps://en.wikibooks.org/wiki/Embedded_Systems/Mixed_C_and_Assembly_Programming

© www.soinside.com 2019 - 2024. All rights reserved.