尝试用float32运算器实现二个大数的加法

尝试用float32运算器实现二个大数的加法

本文尝试用float32运算器实现二个大数的加法。先试图训练一个conv的kernel来实现,不能收敛;最后用float32的向量操作来实现

import numpy as np
import struct
import torch.nn as nn
import torch
import torch.optim as optim

def gen_rand_value(sz):
    return int(''.join('{:d}'.format(np.random.randint(0,10)) for _ in range(sz)))

def to_numpy_array(value,max_len=32):
    # 计算需要多少字节来表示这个整数
    # 注意,这里使用的是向上取整的方式计算字节数
    byte_length = (value.bit_length() + 7) // 8

    # 转换成字节序列
    byte_data = value.to_bytes(byte_length, 'big')

    # 将字节序列转换成uint8的numpy数组
    np_array = np.frombuffer(byte_data, dtype=np.uint8).astype(np.float32)
    
    # 补齐
    padded_arr = np.pad(np_array,(max_len-np_array.shape[0],0))
    return padded_arr

class SimpleConvNet(nn.Module):
    def __init__(self):
        super(SimpleConvNet, self).__init__()
        # 卷积将两个输入通道转换为一个输出通道
        self.conv = nn.Conv2d(1,1, kernel_size=(2,2), stride=(1,1), padding=(0,1),bias=True)

    def forward(self, x):
        x = self.conv(x)
        return x  

# 方案一:不能收敛,不可行
def train_cnn_model_for_add():  
    model = SimpleConvNet()
    criterion = nn.MSELoss()
    optimizer = optim.Adam(model.parameters(), lr=0.01)
      
    num_epochs=200000
    for epoch in range(num_epochs):  
        a=gen_rand_value(64)
        b=gen_rand_value(64)
        c=a+b

        #print("%x" % a)
        #print("%x" % b)
        #print("%x" % c)

        a_arr = to_numpy_array(a)
        b_arr = to_numpy_array(b)
        c_arr = to_numpy_array(c,33)
        #print(c_arr)

        input_arr=np.vstack((a_arr,b_arr))
        #print(input_arr.shape)
        #print(c_arr.shape)

        #(1,1,2,27)
        inputs = torch.from_numpy(input_arr).unsqueeze(0).unsqueeze(0)
        labels=torch.from_numpy(c_arr).unsqueeze(0)
        #print(inputs.shape,labels.shape)

        outputs = model(inputs)
        #print(outputs.shape)
        loss = criterion(outputs, labels)

        # 反向传播和优化
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if epoch%1000==0:
             print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

# 方案二: 用float32的向量操作实现

# 定义最大计算长度
max_len=32
# 定义uint8最大值
max_value=np.ones((max_len),dtype=np.float32)*256

for epoch in range(10000):
    
    # 设置随机种子,方便复现问题
    np.random.seed(epoch)
    
    # 随机数生成长度为64的十进制大数
    a=gen_rand_value(64)
    b=gen_rand_value(64)

    # 用python实现二个大数相加,做为Ground Truth
    c_gt=a+b

    # 将大数按uint8切分成向量,并转换为float类型
    a_arr = to_numpy_array(a,max_len)
    b_arr = to_numpy_array(b,max_len)
    c_gt_arr = to_numpy_array(c_gt,max_len)         
    
    # a、b二个向量相加
    sum_ab=a_arr+b_arr
    
    # 为了去掉循环中的判断,这里假设最多出现10次进位
    for i in range(10):
        # 得到溢出的值(没有溢出为0)
        sum_ab_overflow=sum_ab-max_value
        # 哪些地方溢出了
        overflow_mask=sum_ab_overflow>=0
        #if overflow_mask.sum()==0:  #如果是DSP,可以用判断,提前退出
        #    break            
        sum_ab_overflow=np.maximum(sum_ab_overflow, 0, sum_ab_overflow)
        # 没有溢出的地方,保留它的值
        sum_ab=sum_ab*(overflow_mask==0)
        
        # 进位标记
        carry_flag=np.zeros((max_len),dtype=np.float32)
        carry_flag[0:max_len-1]=np.array(overflow_mask[1:max_len])

        # 计算结果=溢出情况下的值 + 没有溢出时的位 + 进位的值
        sum_ab=sum_ab_overflow+sum_ab+carry_flag

    # 跟Ground Truth比较误差
    if (sum_ab-c_gt_arr).sum()!=0:
        print(f"epoch:{epoch} error")
        print((sum_ab-c_gt_arr).sum())
        print(sum_ab)
        print(c_gt_arr)
        break
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hi20240217

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值