如何解决为什么我的 aks prime test 的实现比我的 naive 版本的实现慢?
我尝试比较多种算法以找到“i”下的最大素数。 但是当我测试实现时,“aks”比我的天真实现慢。 我在想 aks 是素性测试的更好实现,我弄错了吗?
def expand_x_1(n):
c =1
for i in range(n//2+1):
c = c*(n-i)//(i+1)
yield c
def aks(p):
if p==2:
return True
for i in expand_x_1(p):
if i % p:
return False
return True
def all_factors(x): # naive version
i = 2
s = int(x ** 0.5)
while i < s:
if x % i == 0:
return False
i += 1
return True
def find(i,func) :
while not func(i) :
i -= 1
print(i)
%time find(2**16,aks)
%time find(2**16,all_factors)
我尝试比较两者并获得:
- 对于 aks
65521
CPU times: user 1.7 s,sys: 3.24 ms,total: 1.7 s
Wall time: 1.7 s
- 对于 all_factor
65521
CPU times: user 81 µs,sys: 0 ns,total: 81 µs
Wall time: 83.9 µs
解决方法
当输入是质数时,using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using FTD2XX_NET;
namespace PruebaBarbaro
{
public partial class Prueba : Form
{
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
FTDI myFtdiDevice = new FTDI();
byte[] dato = new byte[1];
byte[] datord = new byte[128];
uint numBytesWritten,numBytesAvailable;
UInt32 numBytesRead = 0;
public Prueba()
{
InitializeComponent();
}
private void btnConnect_Click(object sender,EventArgs e)
{
ftStatus = myFtdiDevice.GetNumberOfDevices(ref ftdiDeviceCount);
if (ftStatus==FTDI.FT_STATUS.FT_OK)
{
lblNumDev.Text = ftdiDeviceCount.ToString();
lblNumDev.Visible = true;
}
else
{
lblNumDev.Text = "Failed to get number of devices";
lblNumDev.Visible = true;
}
// Allocate storage for device info list
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
// Populate our device list
ftStatus = myFtdiDevice.GetDeviceList(ftdiDeviceList);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
for (int i = 0; i < ftdiDeviceCount; i++)
{
if (ftdiDeviceList[i].SerialNumber.ToString() == "FTCB4217")
{
lblDescription.Text = ftdiDeviceList[i].Description.ToString();
lblDescription.Visible = true;
ftStatus = myFtdiDevice.OpenBySerialNumber(ftdiDeviceList[i].SerialNumber);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
lblerror.Text = "Failed to open device";
}
}
}
}
ftStatus = myFtdiDevice.SetBaudRate(921600);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
lblerror.Text = "Failed to set Baud Rate";
lblerror.Visible = true;
}
}
private void btnTx_Click(object sender,EventArgs e)
{
dato[0] = 1;
ftStatus = myFtdiDevice.Write(dato,1,ref numBytesWritten);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
lblerror.Text = "Failed to write to device";
lblerror.Visible = true;
}
else
{
lblDataTx.Text = dato[0].ToString();
lblTx.Text = numBytesWritten.ToString();
lblTx.Visible = true;
lblDataTx.Visible = true;
}
do
{
ftStatus = myFtdiDevice.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
lblerror.Text = "Failed to get number of bytes available to read";
lblerror.Visible = true;
}
} while (numBytesAvailable == 0);
lblbytesRx.Text = numBytesAvailable.ToString();
numBytesAvailable = 128;
lblbytesRx.Visible = true;
ftStatus = myFtdiDevice.Read(datord,128,ref numBytesRead);
if(numBytesRead==128)
{
lblValueRx.Text = datord[0].ToString();
lblValueRx.Visible = true;
}
}
private void btnDisconnect_Click(object sender,EventArgs e)
{
lblDataTx.Visible = false;
lblValueRx.Visible = false;
lblbytesRx.Visible = false;
lblerror.Visible = false;
lblTx.Visible = false;
lblDescription.Visible = false;
lblNumDev.Visible = false;
ftStatus = myFtdiDevice.Close();
}
}
}
最终会产生所有可能的 expand_x_1(n)
结果,但 n//2+1
中的循环只循环了大约 all_factors(n)
次。这就是一个巨大的差异。
但也很重要:
sqrt(n)
在迭代中无限增长。添加
c = c*(n-i)//(i+1)
在 print(c.bit_length())
之前,您会看到 yield
在完成之前正在对超过 65000 位宽的整数进行算术运算。这也比这贵得多
16 位算术 find(65521,aks)
可以。
注意:在实践中,没有人使用 AKS 素性测试,因为即使是由世界级数学家大规模优化的版本也比替代方案慢。有关详情,请参阅 AKS Primes algorithm in Python。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。