导航:首页 > 编程语言 > 半隐式法python

半隐式法python

发布时间:2023-01-10 17:27:10

‘壹’ python是什么

Python由荷兰数学和计算机科学研究学会的Guido van Rossum 于1990
年代初设计,作为一门叫做ABC语言的替代品。Python提供了高效的高级数据结构,还能简单有效地面向对象编程。Python语法和动态类型,以及解释型语言的本质,使它成为多数平台上写脚本和快速开发应用的编程语言,随着版本的不断更新和语言新功能的添加,逐渐被用于独立的、大型项目的开发。
Python解释器易于扩展,可以使用C或C++(或者其他可以通过C调用的语言)扩展新的功能和数据类型。Python
也可用于可定制化软件中的扩展程序语言。Python丰富的标准库,提供了适用于各个主要系统平台的源码或机器码。

‘贰’ python 怎么样隐式函数调用

最常用的是在类定义的方法,给一个property的装饰器,可以安装调用属性的方式调用

‘叁’ python中指定参数问题

start,stop=0,start

与下面是等价的

temp=start
start=0
stop=temp

第一种写法是python的一个特性,在后台做了与第二种写法同样的事,只是python把这些动作隐藏了,目的是让代码更简洁

‘肆’ 如何利用Python做简单的验证码识别

1摘要

验证码是目前互联网上非常常见也是非常重要的一个事物,充当着很多系统的防火墙功能,但是随时OCR技术的发展,验证码暴露出来的安全问题也越来越严峻。本文介绍了一套字符验证码识别的完整流程,对于验证码安全和OCR识别技术都有一定的借鉴意义。

然后经过了一年的时间,笔者又研究和get到了一种更强大的基于CNN卷积神经网络的直接端到端的验证识别技术(文章不是我的,然后我把源码整理了下,介绍和源码在这里面):

基于python语言的tensorflow的‘端到端’的字符型验证码识别源码整理(github源码分享)

2关键词

关键词:安全,字符图片,验证码识别,OCR,Python,SVM,PIL

3免责声明

本文研究所用素材来自于某旧Web框架的网站完全对外公开的公共图片资源。

本文只做了该网站对外公开的公共图片资源进行了爬取,并未越权做任何多余操作。

本文在书写相关报告的时候已经隐去漏洞网站的身份信息。

本文作者已经通知网站相关人员此系统漏洞,并积极向新系统转移。

本报告的主要目的也仅是用于OCR交流学习和引起大家对验证安全的警觉。

4引言

关于验证码的非技术部分的介绍,可以参考以前写的一篇科普类的文章:

互联网安全防火墙(1)--网络验证码的科普

里面对验证码的种类,使用场景,作用,主要的识别技术等等进行了讲解,然而并没有涉及到任何技术内容。本章内容则作为它的技术补充来给出相应的识别的解决方案,让读者对验证码的功能及安全性问题有更深刻的认识。

5基本工具

要达到本文的目的,只需要简单的编程知识即可,因为现在的机器学习领域的蓬勃发展,已经有很多封装好的开源解决方案来进行机器学习。普通程序员已经不需要了解复杂的数学原理,即可以实现对这些工具的应用了。

主要开发环境:

‘伍’ python构成一个程序最基本的三部分

python程序可以分解为模块、语句、表达式和对象四部分
1,模块包含语句
2,语句包含表达式
3,表达式建立并处理对象

‘陆’ 小白入门:用什么写Python

怎么学python

俗话说得好,“摩天大楼从地起”,学习任何编程语言都一定要把该语言的基础打牢,而怎么打地基呢?秘诀只有一条:多敲代码多敲代码多敲代码。学习前期建议找一本讲python基础的书或博客,把里面的例题跟着操作一遍,在基础打扎实后,可上一些比较出名的竞赛项目的网站如kaggle等,通过做项目去巩固知识。

推荐书籍:《Python基础教程(第3版)》Magnus Lie Hetland着

推荐理由:全面介绍了Python的基础知识、基本概念,高级主题,还有Python程序测试、打包、发布等知识,及10个具有实际意义的Python项目的开发过程,涉及的范围较广,既能为初学者夯实基础,又能帮助程序员提升技能,适合各个层次的Python开发人员阅读参考。

基础知识

代码规范

1. 缩进

相比于其他语言用大括号和end来标识代码块,python语言比较“独特”,其通过代码的缩进来标识所属代码块,通常4个空格为一个缩进,可用tab键实现。缩进是python代码的重要组成部分,若你的代码缩进格式不正确,如同一段代码块语句缩进不一致,首句未顶格等,都会运行出错。

#一个完整的语句首句要顶格

i=0

#同一代码块的语句应缩进一致

for i in range(5):

print(i)

i+=1

2. 注释

编程语言的注释,即对代码的解释和说明。给代码加上注释,可提高代码的可读性,当你阅读一段他人写的代码时,通过注释迅速掌握代码的大致意思,读起代码将更加得心应手。

python语言的注释分为单行注释和多行注释,在注释符后的内容计算机会自动跳过不去执行。

单行注释:在需注释语句前加“#”,可在代码后使用,也可另起一行使用

i=1 #在代码后使用注释

#另起一行使用注释

多行注释:在语句开头和结尾处加三个单引号或三个双引号(前后须一致)

'''

使用单引号的多行注释

'''

"""

使用双引号的多行注释

"""

使用注释除了起到望文生义,迅速了解代码意思的作用外,还有一个小妙处,可以将某段未完成或需要修改的代码隐蔽起来,暂时不让计算机执行。

2. 输入语句

在python中获取键盘输入数据的函数是input()函数,input函数会自动将输入的数据转为字符串类型,并自动忽略换行符,同时可给出提示字符串。如果需要得到其他类型的数据,可对其进行强制性类型转换。

input( )语法:

input([prompt])

input( )参数:

prompt: 给输入者的提示信息,可选参数age=input("请输入您的年龄:")

‘柒’ 隐式马尔科夫模型 及 Python + HMMlearn的使用

hmmlearn

隐式马尔科夫模型Hidden Markov Models(HMMs) 是一种通用的概率模型。一个可观测的变量X的序列被一个内部的隐藏状态Z所生成。其中,隐藏状态Z无法被直接观测。在隐藏状态之间的转移被假设是通过 马尔科夫链(Markov chain) 的形式。
模型可以表示为 起始概率向量 和转移概率矩阵 . 一个观测量生成的概率可以是关于 的任意分布, 基于当前的隐藏状态。

HMMs的3个基本问题:

hmmlearn 是Python支持HMMs的包。原来是sklearn的一部分,后来由于接口不一致分成单独的包了。不过使用起来和sklearn的其他模型类似。

构造HMM model:

初始化的参数主要有 n_components , covariance_type , n_iter 。每个参数的作用我还没有研究。

通过 fit 方法。
输入是一个矩阵,包含拼接的观察序列concatenated sequences of observation (也就是samples),和序列的长度。

EM算法是背后拟合模型的算法。基于梯度优化的方法。通常会卡到一个局部极优值上。通常用户需要用不同的初始化跑多次 fit ,然后选择分数最高的模型。

分数通过 score 方法计算。
推导出的最优的隐藏状态可以调用 predict 方法获得。 predict 方法可以指定解码器算法。当前支持的有 viterbi (Vierbi algorithm)和 map (posteriori estimation)。

‘捌’ 如何解决python2不能隐式继承

继承是所有开发语言的必修内容,而本文写的只是Python继承中的特殊之处,关于继承概念及内容可以自行网络(不装B,感觉网络挺好的)1.构造函数:
要说继承,先要说一下构造函数。Java要求是与类名相同并且无返回值,而Python则是强制要求命名为“__init__()”。
当创建类的对象时,会自动先调用构造函数,一般用于初始化。构造函数可以不写,那么程序会隐式自动增加一个空的构造函数。
2.继承写法:
(1).class 空格 类名称 括号内填写父类名 冒号具体写法如下class A:
def __init__(self):
pass
def print_class_name(self):
print "this is class A"
class B(A):
def __init__(self):
pass
if __name__ == "__main__":
class_b = B()
class_b.print_class_name()
上面代码首先定义了一个名为“A”的类,包含一个名为“print_class_name”的方法。然后,定义一个名为“B”的类,继承“A”,同时继承了“A”类的“print_class_name”的方法。
此时“A”类为“B”类的父类或者叫基类,“B”类是“A”类的子类,子类会继承父类的所有公共方法。
(2).意义:
一字记之曰“懒!”(感叹号不算字)我始终相信赖人才能推动科学进步。
言归正传,假如你要写一个老王类,包含年龄、性别等方法,后面还要写一个老王的儿子小王类,也有年龄、性别等方法?
class FatherWang:
def __init__(self, age=43, sex='man'):
self.a = age
self.s = sex
def age(self):
print self.a
def sex(self):
print self.s
class SonWang:
def __init__(self, age=13, sex='man'):
self.a = age
self.s = sex
def age(self):
print self.a
def sex(self):
print self.s
if __name__ == "__main__":
father = FatherWang(43, "man")
father.age()
father.sex()
son = SonWang(13, "man")
son.age()
son.sex()
你会发现两个类中有相同名称和功能的方法,这样写岂不是很重复很累?(尽管按键盘次数不算太多,我依然觉得很累)如果有继承就很好解决了。
class FatherWang:
def __init__(self, age=43, sex='man'):
self.a = age
self.s = sex
def age(self):
print self.a
def sex(self):
print self.s
class SonWang(FatherWang):
def __init__(self, age=13, sex='man'):
FatherWang.__init(age, sex)
if __name__ == "__main__":
father = FatherWang(43, "man")
father.age()
father.sex()
son = SonWang(13, "man")
son.age()
son.sex()
两者运行结果完全一样,但是使用继承方法却省了很多按键盘的次数。
3.经典类与新式类:
(1)经典类写法:
class A:
pass
(2)新式类写法:
class A(object):
pass
可以看出,新式类和经典类的区别在于,是否继承object这个基类。object是所有类的父类。所以之前不带“(object)”的写法,属于经典类写法,加上“(object)”就是新式类的写法。
(3).原因:这里我得吐槽一下Python的版本混乱。2.2版本之前只有经典类写法,这里有一个问题,代码如下?
class A:
pass
class B(object):
pass
a = A()
b = B()
print a.__class__
print type(a)
print "----------"
print b.__class__
print type(b)
结果为:
__main__.A
<type 'instance'>
----------
<class '__main__.B'>
<class '__main__.B'>
首先A类为经典类,B类为新式类。__class__属性和type()方法都是返回对象类型,那么问题来了,使用经典类的写法返回结果却不一致。因此在2.2版本之后出现了新式类来解决这个问题,自然,新式类和经典类还有更大的区别在后面说。另外在3.3版本中,无论使用哪种写法,python都会隐式的继承object,所以3.3版本不会再有经典类(在这里我只想问,早干什么去了!),但是鉴于3.3兼容性问题,貌似没有太多人用。
4.方法重写与方法重载
(1).方法重写:
class FatherWang:
def __init__(self, age=43, sex='man'):
self.a = age
self.s = sex
def age(self):
print self.a
def sex(self):
print self.s
def name(self):
print "Wang_yang"
class SonWang(FatherWang):
def __init__(self, age=13, sex='man'):
FatherWang.__init(age, sex)
def name(self):
print "Wang_xiaoming"
if __name__ == "__main__":
father = FatherWang(43, "man")
father.age()
father.sex()
father.name()
son = SonWang(13, "man")
son.age()
son.sex()
son.name()
比继承写法(2)中的代码相比,两个类分别多了同名的方法“name”,之前说过子类会继承父类的方法,那么这时候两个类有相同名字的方法,冲突了,怎么处理?
这个时候,就叫方法重写。可以理解为,子类的“name”方法把父类的“name”方法覆盖了,重新写了,所以调用子类的“name”方法时,会以子类的为准(尽管这种理解并不准确,但是可以很好解释“方法重写”这个名词,后面会讲到正确理解)。
注意下面的代码
class FatherWang:
def __init__(self, age=43, sex="man"):
self.a = age
self.s = sex
print "I am FatherWang"
def age(self):
print "Father age:"+str(self.a)
def sex(self):
print "Father sex:"+str(self.s)
class MotherLi:
def __init__(self, age=40, sex="woman"):
self.a = age
self.s = sex
print "I am MotherLi"
def age(self):
print "Mother age:"+str(self.a)
def sex(self):
print "Mother sex"+str(self.s)
class SonWang(FatherWang, MotherLi):
def __init__(self, age=13, sex="man"):
FatherWang.__init__(self, age, sex)
MotherLi.__init__(self, age, sex)
print "I am SonWang"
if __name__ == "__main__":
son = SonWang()
son.age()
son.sex()
执行结果:
I am FatherWang
I am MotherLi
I am SonWang
Father age:13
Father sex:man
在之前代码上稍作修改,另外增加了一个MotherLi的类,SonWang类继承了FatherWang类和MotherLi类。注意,这是经典类的写法。
首先,我们知道了python多继承的写法,就是在括号中上一个父类后面加个逗号,然后再写上下一个父类的名字:
class SonWang(FatherWang, MotherLi):
其次,FatherWang类和MotherLi类,都有名为age和sex方法,SonWang类为什么会继承FatherWang类的方法呢?那么把SonWang类的继承顺序改一下class SonWang(MotherLi, FatherWang):
就会发现继承的是MotherLi类的方法。
通过结果可知,是按照继承的顺序。
让我们把代码结构变得更发杂一些吧,我想会崩溃的,哈哈哈?
class Grandfather:
def __init__(self, age=73, sex="man"):
self.a = age
self.s = sex
print "I am Grandfather"
def age(self):
print "Grandfather age:"+str(self.a)
def sex(self):
print "Grandfather sex:"+str(self.s)
def Interesting(self):
print "Grandfather Interesting"
class Grandmother:
def __init__(self, age=70, sex="woman"):
self.a = age
self.s = sex
print "I am Grandmother"
def age(self):
print "Grandmother age:"+str(self.a)
def sex(self):
print "Grandmother sex:"+str(self.s)
def Interesting(self):
print "Grandmother Interesting"
class FatherWang(Grandfather, Grandmother):
def __init__(self, age=43, sex="man"):
self.a = age
self.s = sex
Grandfather.__init__(self, age, sex)
Grandmother.__init__(self, age, sex)
print "I am FatherWang"
def age(self):
print "Father age:"+str(self.a)
def sex(self):
print "Father sex:"+str(self.s)
class MotherLi(Grandfather, Grandmother):
def __init__(self, age=40, sex="woman"):
self.a = age
self.s = sex
Grandfather.__init__(self, age, sex)
Grandmother.__init__(self, age, sex)
print "I am MotherLi"
def age(self):
print "Mother age:"+str(self.a)
def sex(self):
print "Mother sex"+str(self.s)
def Interesting(self):
print "MotherLi Interesting"
class SonWang(FatherWang, MotherLi):
def __init__(self, age=13, sex="man"):
FatherWang.__init__(self, age, sex)
MotherLi.__init__(self, age, sex)
print "I am SonWang"
if __name__ == "__main__":
son = SonWang()
son.age()
son.sex()
son.Interesting()
执行结果:
I am Grandfather
I am Grandmother
I am FatherWang
I am Grandfather
I am Grandmother
I am MotherLi
I am SonWang
Father age:13
Father sex:man
Grandfather Interesting
话说,我自己都有点儿晕。简单来讲,就是儿子继承了老爸、老妈,然后老爸继承了爷爷、奶奶,妈妈继承了老爷、姥姥。(真是一大家子啊)通过执行结果可知,儿子类先找到老爸类,然后再找老爸类的第1个父类爷爷类,此时发现爷爷类没有父类了,那么执行初始化。然后还要继续找到老爸类的第2个父类奶奶类,此时发现奶奶类没有父类了,执行初始化。此时老爸类的所有父类都初始化完成,初始化自己。然后开始找妈妈类……那么为什么Interesting方法会使用爷爷类的呢?奶奶类、老爷类、姥姥类都有啊?首先儿子类没有Interesting方法,会先找第1个父类老爸类。发现老爸类也没有,再找老爸类的第1个父类,发现找到了,那么就直接调用不再往下找了。
结论:经典类的多继承,按照继承顺序查找。即,从左到右,从下到上的方式。注意,只有经典类是这样的!
(2).新式类的多继承:
class Grandfather(object):
def __init__(self, age=73, sex="man"):
self.a = age
self.s = sex
print "I am Grandfather"
def age(self):
print "Grandfather age:"+str(self.a)
def sex(self):
print "Grandfather sex:"+str(self.s)
def Interesting(self):
print "Grandfather Interesting"
class Grandmother(object):
def __init__(self, age=70, sex="woman"):
self.a = age
self.s = sex
print "I am Grandmother"
def age(self):
print "Grandmother age:"+str(self.a)
def sex(self):
print "Grandmother sex:"+str(self.s)
def Interesting(self):
print "Grandmother Interesting"
class FatherWang(Grandfather, Grandmother):
def __init__(self, age=43, sex="man"):
self.a = age
self.s = sex
Grandfather.__init__(self, age, sex)
Grandmother.__init__(self, age, sex)
print "I am FatherWang"
def age(self):
print "Father age:"+str(self.a)
def sex(self):
print "Father sex:"+str(self.s)
class MotherLi(Grandfather, Grandmother):
def __init__(self, age=40, sex="woman"):
self.a = age
self.s = sex
Grandfather.__init__(self, age, sex)
Grandmother.__init__(self, age, sex)
print "I am MotherLi"
def age(self):
print "Mother age:"+str(self.a)
def sex(self):
print "Mother sex"+str(self.s)
def Interesting(self):
print "MotherLi Interesting"
class SonWang(FatherWang, MotherLi):
def __init__(self, age=13, sex="man"):
FatherWang.__init__(self, age, sex)
MotherLi.__init__(self, age, sex)
print "I am SonWang"
if __name__ == "__main__":
son = SonWang()
son.age()
son.sex()
son.Interesting()
执行结果:
I am Grandfather
I am Grandmother
I am FatherWang
I am Grandfather
I am Grandmother
I am MotherLi
I am SonWang
Father age:13
Father sex:man
MotherLi Interesting

‘玖’ Python中文分词的原理你知道吗

中文分词,即 Chinese Word Segmentation,即将一个汉字序列进行切分,得到一个个单独的词。表面上看,分词其实就是那么回事,但分词效果好不好对信息检索、实验结果还是有很大影响的,同时分词的背后其实是涉及各种各样的算法的。

中文分词与英文分词有很大的不同,对英文而言,一个单词就是一个词,而汉语是以字为基本的书写单位,词语之间没有明显的区分标记,需要人为切分。根据其特点,可以把分词算法分为四大类:

基于规则的分词方法

基于统计的分词方法

基于语义的分词方法

基于理解的分词方法

下面我们对这几种方法分别进行总结。

基于规则的分词方法

这种方法又叫作机械分词方法、基于字典的分词方法,它是按照一定的策略将待分析的汉字串与一个“充分大的”机器词典中的词条进行匹配。若在词典中找到某个字符串,则匹配成功。该方法有三个要素,即分词词典、文本扫描顺序和匹配原则。文本的扫描顺序有正向扫描、逆向扫描和双向扫描。匹配原则主要有最大匹配、最小匹配、逐词匹配和最佳匹配。

最大匹配法(MM)。基本思想是:假设自动分词词典中的最长词条所含汉字的个数为 i,则取被处理材料当前字符串序列中的前 i 个字符作为匹配字段,查找分词词典,若词典中有这样一个 i 字词,则匹配成功,匹配字段作为一个词被切分出来;若词典中找不到这样的一个 i 字词,则匹配失败,匹配字段去掉最后一个汉字,剩下的字符作为新的匹配字段,再进行匹配,如此进行下去,直到匹配成功为止。统计结果表明,该方法的错误率 为 1/169。

逆向最大匹配法(RMM)。该方法的分词过程与 MM 法相同,不同的是从句子(或文章)末尾开始处理,每次匹配不成功时去掉的是前面的一个汉字。统计结果表明,该方法的错误率为 1/245。

逐词遍历法。把词典中的词按照由长到短递减的顺序逐字搜索整个待处理的材料,一直到把全部的词切分出来为止。不论分词词典多大,被处理的材料多么小,都得把这个分词词典匹配一遍。

设立切分标志法。切分标志有自然和非自然之分。自然切分标志是指文章中出现的非文字符号,如标点符号等;非自然标志是利用词缀和不构成词的词(包 括单音词、复音节词以及象声词等)。设立切分标志法首先收集众多的切分标志,分词时先找出切分标志,把句子切分为一些较短的字段,再用 MM、RMM 或其它的方法进行细加工。这种方法并非真正意义上的分词方法,只是自动分词的一种前处理方式而已,它要额外消耗时间扫描切分标志,增加存储空间存放那些非 自然切分标志。

最佳匹配法(OM)。此法分为正向的最佳匹配法和逆向的最佳匹配法,其出发点是:在词典中按词频的大小顺序排列词条,以求缩短对分词词典的检索时 间,达到最佳效果,从而降低分词的时间复杂度,加快分词速度。实质上,这种方法也不是一种纯粹意义上的分词方法,它只是一种对分词词典的组织方式。OM 法的分词词典每条词的前面必须有指明长度的数据项,所以其空间复杂度有所增加,对提高分词精度没有影响,分词处理的时间复杂度有所降低。

此种方法优点是简单,易于实现。但缺点有很多:匹配速度慢;存在交集型和组合型歧义切分问题;词本身没有一个标准的定义,没有统一标准的词集;不同词典产生的歧义也不同;缺乏自学习的智能性。

基于统计的分词方法

该方法的主要思想:词是稳定的组合,因此在上下文中,相邻的字同时出现的次数越多,就越有可能构成一个词。因此字与字相邻出现的概率或频率能较好地反映成词的可信度。可以对训练文本中相邻出现的各个字的组合的频度进行统计,计算它们之间的互现信息。互现信息体现了汉字之间结合关系的紧密程度。当紧密程 度高于某一个阈值时,便可以认为此字组可能构成了一个词。该方法又称为无字典分词。

该方法所应用的主要的统计模型有:N 元文法模型(N-gram)、隐马尔可夫模型(Hiden Markov Model,HMM)、最大熵模型(ME)、条件随机场模型(Conditional Random Fields,CRF)等。

在实际应用中此类分词算法一般是将其与基于词典的分词方法结合起来,既发挥匹配分词切分速度快、效率高的特点,又利用了无词典分词结合上下文识别生词、自动消除歧义的优点。

基于语义的分词方法

语义分词法引入了语义分析,对自然语言自身的语言信息进行更多的处理,如扩充转移网络法、知识分词语义分析法、邻接约束法、综合匹配法、后缀分词法、特征词库法、矩阵约束法、语法分析法等。

扩充转移网络法

该方法以有限状态机概念为基础。有限状态机只能识别正则语言,对有限状态机作的第一次扩充使其具有递归能力,形成递归转移网络 (RTN)。在RTN 中,弧线上的标志不仅可以是终极符(语言中的单词)或非终极符(词类),还可以调用另外的子网络名字分非终极符(如字或字串的成词条件)。这样,计算机在 运行某个子网络时,就可以调用另外的子网络,还可以递归调用。词法扩充转移网络的使用, 使分词处理和语言理解的句法处理阶段交互成为可能,并且有效地解决了汉语分词的歧义。

矩阵约束法

其基本思想是:先建立一个语法约束矩阵和一个语义约束矩阵, 其中元素分别表明具有某词性的词和具有另一词性的词相邻是否符合语法规则, 属于某语义类的词和属于另一词义类的词相邻是否符合逻辑,机器在切分时以之约束分词结果。

基于理解的分词方法

基于理解的分词方法是通过让计算机模拟人对句子的理解,达到识别词的效果。其基本思想就是在分词的同时进行句法、语义分析,利用句法信息和语义信息来处理歧义现象。它通常包括三个部分:分词子系统、句法语义子系统、总控部分。在总控部分的协调下,分词子系统可以获得有关词、句子等的句法和语义信息来对分词歧义进行判断,即它模拟了人对句子的理解过程。这种分词方法需要使用大量的语言知识和信息。目前基于理解的分词方法主要有专家系统分词法和神经网络分词法等。

专家系统分词法

从专家系统角度把分词的知识(包括常识性分词知识与消除歧义切分的启发性知识即歧义切分规则)从实现分词过程的推理机中独立出来,使知识库的维护与推理机的实现互不干扰,从而使知识库易于维护和管理。它还具有发现交集歧义字段和多义组合歧义字段的能力和一定的自学习功能。

神经网络分词法

该方法是模拟人脑并行,分布处理和建立数值计算模型工作的。它将分词知识所分散隐式的方法存入神经网络内部,通过自学习和训练修改内部权值,以达到正确的分词结果,最后给出神经网络自动分词结果,如使用 LSTM、GRU 等神经网络模型等。

神经网络专家系统集成式分词法

该方法首先启动神经网络进行分词,当神经网络对新出现的词不能给出准确切分时,激活专家系统进行分析判断,依据知识库进行推理,得出初步分析,并启动学习机制对神经网络进行训练。该方法可以较充分发挥神经网络与专家系统二者优势,进一步提高分词效率。

以上便是对分词算法的基本介绍。

‘拾’ 如何用Python编写一个素数环

此文主要目的,是向大家展示如何才能用python语言,来部署STARK算法。
STARKs(可扩容的透明知识论证)是创建一种证明的技术,这项证明中f(x)=y,其中f可能要花很长的时间来进行计算,但是这个证明可以被很快验证。STARK是“双重扩容”:对于一个需要t步骤的计算,这会花费大约O(t * log(t))步骤才能完成这个证明,这可能是最优的情况,而且这需要通过~O(log2(t))个步骤才能验证,对于中等大小的T值,它比原始计算快得多。STARKs也拥有隐私保护的“零知识证明”的特性,虽然我们将这类使用案例应用到其中,从而完成可验证的延迟功能,不需要这类性质,所以我们不用担心。
首先,先请几项说明:
这个代码还没有完全审核;在实际使用案例中的情况,还不能保证
这部分代码是还没有达到理想状态(是用Python语言写的)
STARKs 的“真实情况” 倾向于使用二进制字段而不是素数域的特定应用程序效率的原因;但是,他们确实也表现出,这里写出的代码是合法并且可用的。
没有一个真实的方法来使用STARK。它是一个非常宽泛的加密和数学架构,同时为不同的应用有不同的设置,以及连续的研究来减少证明者和验证者的复杂性,同时提高可用性。
此文希望大家能够知道,模运算和素数域是如何运行的,
并且和多项式概念,插值和估值进行结合。
现在,让我们一起来了解吧!
MIMC
下面是STARK的功能展示:
def mimc(inp, steps, round_constants): start_time = time.time() for i in range(steps-1): inp = (inp**3 + round_constants[i % len(round_constants)]) % molus print("MIMC computed in %.4f sec" % (time.time() - start_time)) return inp
我们选择MIMC作为案例,因为它(i)很容易理解,(ii)在真实世界使用的很多。函数功能见下图:
注意:在很多关于MIMC的讨论中,你可以典型地看出使用了XOR,而不是+;这是因为MIMC可以在二进制情况下使用,其中添加是XOR;这里我们会在素数领域进行。
在我们的案例中,常数相对而言会是比较小的列表(例如,64位),这会一直连续地进行周期循环(也就说,在k[64]之后)。MIMC自身可以获得这个特性,因为MIMC可以向后进行计算(从相应的输出获得输入),但是往后计算需要比向前计算多花费100倍的时间(并且没有方向可以同步进行)。所以你可以将往后计算的功能想象成计算不能同步的工作量证明,并且往前方向计算的功能可以作为验证的过程。
x -> x(2p-1)/3 是x -> x3 的反函数;根据费马小定理,这是真实的,尽管这个定理没有费马大定理出名,但是依然对数学的贡献很大。
我们尝试使用STARK来进行更加有效的验证,而不是让验证者必须在向前方向运行MIMC,在完成向后计算之后,证明者可以在向前方向进行STARK计算,并且验证者可以很简单地验证STARK。我们希望计算STARK可以比MIMC向前和向后之间的运行速度差别要小,所以证明者的时间仍然是有初始的向后计算来主导的。而并不是STARK计算。STARK的认证会相对较快(在python语言算法中,可以是0.05-0.3秒),不论初始的计算时间有多长。
所有的计算会在2256 – 351 * 232 + 1个模内完成;我们使用素数模,因为它是小于2256 最大的素数,其中乘法群包含了232 个子集(也就是说,有这样一个数g,从而在完全232次循环之后,G素数环的连续幂模绕回到1),而且是按照6k+5的形式。首个特性是保证FFT和FRI算法的有效版本,其次是保证MIMC实际上可以向后计算(请见上面提到的x -> x(2p-1)/3 使用方法)。
素域操作
我们通过建立方便的等级来进行素域的操作,同时也有多项式的操作。代码如下,收首先是小数位数:
class PrimeField(): def __init__(self, molus): # Quick primality test assert pow(2, molus, molus) == 2 self.molus = molus def add(self, x, y): return (x+y) % self.molus def sub(self, x, y): return (x-y) % self.molus def mul(self, x, y): return (x*y) % self.molus
并且使用扩展欧几里得算法,来计算模块逆转(这和在素域中计算1/x相同):
# Molar inverse using the extended Euclidean algorithm def inv(self, a): if a == 0: return 0 lm, hm = 1, 0 low, high = a % self.molus, self.molus while low > 1: r = high//low nm, new = hm-lm*r, high-low*r lm, low, hm, high = nm, new, lm, low return lm % self.molus
上面的算法是相对昂贵的;幸运地是,对于特定的案例,我们需要做很多的模逆计算,有一个数学方法可以让我们来计算很多逆运算,被称为蒙哥马利批量求逆:
使用蒙哥马利批量求逆来计算模逆,其输入为紫色,输出为绿色,乘法门为黑色,红色方块是唯一的模逆。
下面的代码是算法的体现,其中包含一些特别的逻辑。如果我们正在求逆的集合中包含零,那么它会将这些零的逆设置为 0 并继续前进。
def multi_inv(self, values): partials = [1] for i in range(len(values)): partials.append(self.mul(partials[-1], values[i] or 1)) inv = self.inv(partials[-1]) outputs = [0] * len(values) for i in range(len(values), 0, -1): outputs[i-1] = self.mul(partials[i-1], inv) if values[i-1] else 0 inv = self.mul(inv, values[i-1] or 1) return outputs
这部分算法接下来会验证称为非常重要的东西,特别是当我们开始和不同阶的多项式进行计算的时候。
现在我们来看看一些多项式计算。我们把多项式当做一个数据集,其中的i是第i阶(例如,x3 + 2x + 1变成[1, 2, 0, 1])。下面就是在一个点进行多项式估算的方法:
# Evaluate a polynomial at a point def eval_poly_at(self, p, x): y = 0 power_of_x = 1 for i, p_coeff in enumerate(p): y += power_of_x * p_coeff power_of_x = (power_of_x * x) % self.molus return y % self.molus
困难和挑战
f.eval_poly_at([4, 5, 6], 2)的输出是多少?模是31吗?
下面的解释就是答案
.其实也有代码是多项式加法,减法,乘法和除法;这是很长的加减乘除运算。有一个很重要的内容是拉格朗日插值,它将一组 x 和 y 坐标作为输入,并返回通过所有这些点的最小多项式(你可以将其视为多项式求值的逆):
# Build a polynomial that returns 0 at all specified xs def zpoly(self, xs): root = [1] for x in xs: root.insert(0, 0) for j in range(len(root)-1): root[j] -= root[j+1] * x return [x % self.molus for x in root] def lagrange_interp(self, xs, ys): # Generate master numerator polynomial, eg. (x - x1) * (x - x2) * ... * (x - xn) root = self.zpoly(xs) # Generate per-value numerator polynomials, eg. for x=x2, # (x - x1) * (x - x3) * ... * (x - xn), by dividing the master # polynomial back by each x coordinate nums = [self.div_polys(root, [-x, 1]) for x in xs] # Generate denominators by evaluating numerator polys at each x denoms = [self.eval_poly_at(nums[i], xs[i]) for i in range(len(xs))] invdenoms = self.multi_inv(denoms) # Generate output polynomial, which is the sum of the per-value numerator # polynomials rescaled to have the right y values b = [0 for y in ys] for i in range(len(xs)): yslice = self.mul(ys[i], invdenoms[i]) for j in range(len(ys)): if nums[i][j] and ys[i]: b[j] += nums[i][j] * yslice return [x % self.molus for x in b]
相关数学知识请参见此文的M-N部分。需要注意,我们也会有特别的方法lagrange_interp_4和lagrange_interp_2来加速次数小于 2 的拉格朗日插值和次数小于 4 的多项式运算。
快速傅立叶变换
如果你仔细阅读上面的算法,你也许会发现拉格朗日插值和多点求值(即求在N个点处次数小于N的多项式的值)都需要耗费2次时间,例如对于1000个点求拉格朗日插值,需要几百万个步骤,而且100万个点的拉格朗日插值需要万亿个步骤。这是不可接受的低效率,所以我们需要使用更加有效的算法,快速傅立叶变换。
FFT只需要花费O(n * log(n))的时间(也就是说,1000个点的计算需要10,000步,100万个点的计算需要2000步),虽然它的范围更受限制;x坐标必须是单位根部的完全集合,必须满足N = 2k 阶。也就是说,如果有N个点,那么x坐标必须某个P值的连续幂,1, p, p2, p3…,其中pN = 1。这个算法能够用来进行多点计算和插值计算,而且只需要调整一个小参数。
下面就是算法详情(这是个简单的表达方式;更详细内容可以参阅此处代码)
def fft(vals, molus, root_of_unity): if len(vals) == 1: return vals L = fft(vals[::2], molus, pow(root_of_unity, 2, molus)) R = fft(vals[1::2], molus, pow(root_of_unity, 2, molus)) o = [0 for i in vals] for i, (x, y) in enumerate(zip(L, R)): y_times_root = y*pow(root_of_unity, i, molus) o[i] = (x+y_times_root) % molus o[i+len(L)] = (x-y_times_root) % molus return o def inv_fft(vals, molus, root_of_unity): f = PrimeField(molus) # Inverse FFT invlen = f.inv(len(vals)) return [(x*invlen) % molus for x in fft(vals, molus, f.inv(root_of_unity))]
你可以自己通过一些输入来运行代码,并且看看是否能得到想要的结果,当你使用eval_poly_at的时候,给出你期望得到的答案。例如:
>>> fft.fft([3,1,4,1,5,9,2,6], 337, 85, inv=True) [46, 169, 29, 149, 126, 262, 140, 93] >>> f = poly_utils.PrimeField(337) >>> [f.eval_poly_at([46, 169, 29, 149, 126, 262, 140, 93], f.exp(85, i)) for i in range(8)] [3, 1, 4, 1, 5, 9, 2, 6]
傅里叶变换会把[x[0] …. x[n-1]]作为输入,并且它的目标是输出x[0] + x[1] + … + x[n-1]作为首个元素,x[0] + x[1] * 2 + … + x[n-1] * w**(n-1)作为第二个元素,等等;快速傅里叶变换可以通过把数据分为两半,来完成这个,在两边都进行FFT,然后将结果结合在一起。
上图就是信息如何进行FFT运算的解释。请注意FFT是如何进行两次数据复制,并且进行粘合,直到你得到一个元素。
现在,我们把所有部分组合起来,看看整件事情是如何:def mk_mimc_proof(inp, steps, round_constants),它生成运行 MIMC 函数的执行结果的证明,其中给定的输入为步骤数。首先,是一些 assert 函数:
# Calculate the set of x coordinates xs = get_power_cycle(root_of_unity, molus) column = [] for i in range(len(xs)//4): x_poly = f.lagrange_interp_4( [xs[i+len(xs)*j//4] for j in range(4)], [values[i+len(values)*j//4] for j in range(4)], ) column.append(f.eval_poly_at(x_poly, special_x))
扩展因子是我们将要拉伸的计算轨迹(执行 MIMC 函数的“中间值”的集合)。
m2 = merkelize(column) # Pseudo-randomly select y indices to sample # (m2[1] is the Merkle root of the column) ys = get_pseudorandom_indices(m2[1], len(column), 40) # Compute the Merkle branches for the values in the polynomial and the column branches = [] for y in ys: branches.append([mk_branch(m2, y)] + [mk_branch(m, y + (len(xs) // 4) * j) for j in range(4)])
我们需要步数乘以扩展因子最多为 2^32,因为当 k > 32 时,我们没有 2^k 次的单位根。
computational_trace_polynomial = inv_fft(computational_trace, molus, subroot) p_evaluations = fft(computational_trace_polynomial, molus, root_of_unity)
我们首个计算会是得出计算轨迹;也就是说,所有的计算中间值,从输入到输出。
assert steps <= 2**32 // extension_factor assert is_a_power_of_2(steps) and is_a_power_of_2(len(round_constants)) assert len(round_constants) < steps
然后,我们会从将计算轨迹转换为多项式,在单位根 g (其中,g^steps = 1)的连续幂的轨迹上“放下”连续值,然后我们对更大的集合——即单位根 g2 的连续幂,其中 g2^steps * 8 = 1(注意 g2^8 = g)的多项式求值。
# Generate the computational trace computational_trace = [inp] for i in range(steps-1): computational_trace.append((computational_trace[-1]**3 + round_constants[i % len(round_constants)]) % molus) output = computational_trace[-1]
黑色: g1 的幂。紫色: g2 的幂。橙色:1。你可以将连续的单位根看作一个按这种方式排列的圆圈。我们沿着 g1的幂“放置”计算轨迹,然后扩展它来计算在中间值处(即 g2 的幂)的相同多项式的值。
我们可以将MIMC的循环常数转换为多项式。因为这些循环常数链是非常通常发生地(在我们的测试中,每64个步骤都会进行),最终证明他们形成了64阶的多项式,而且外面可以很容易计算出它的表达式,以及扩展式:
skips2 = steps // len(round_constants) constants_mini_polynomial = fft(round_constants, molus, f.exp(subroot, skips2), inv=True) constants_polynomial = [0 if i % skips2 else constants_mini_polynomial[i//skips2] for i in range(steps)] constants_mini_extension = fft(constants_mini_polynomial, molus, f.exp(root_of_unity, skips2))
假设其中有8192个步骤,并且有64个循环常数。这是我们想要做的:我们正在进行FFT,从而计算循环常数来作为g1128 的功能。然后我们在之间加入很多零,来完成g1本身的功能。因为g1128 大约每64步进行循环,我们知道g1这个功能也会同样。我们只计算这个扩展中的512个步骤,因为我们知道这个扩展会在每512步之后重复。现在,我们按照斐波那契案例中那样,计算C(P(x)),除了这次是计算,需要注意,我们不在计算使用系数形式的多项式;而是根据高次单位根的连续幂来对多项式进行求值。
c_of_p需要满足Q(x) = C(P(x), P(g1*x),K(x)) = P(g1*x) – P(x)**3 – K(x);目标是对于任何我们放入计算轨道的x(除了最后一步,因为在最后一步之后,就没有步骤),计算轨迹中的下个数值就和之前的相等,再加上循环常量。与第1部分中的斐波那契示例不同,其中如果某个计算步骤是在k向量,下个就会是k+1向量,我们把低次单位根( g1 )的连续幂放下计算轨迹,所以如果某个计算步骤是在x = g1i ,下个步骤就会在g1i+1 = g1i * g1 = x * g1。因此,对于低阶单位根( g1 )的每一个幂,我们希望最终会是P(x*g1) = P(x)**3 + K(x),或者P(x*g1) – P(x)**3 – K(x) = Q(x) = 0。因此,Q(x) 会在低次单位根 g 的所有连续幂上等于零(除了最后一个)。
# Create the composed polynomial such that # C(P(x), P(g1*x), K(x)) = P(g1*x) - P(x)**3 - K(x) c_of_p_evaluations = [(p_evaluations[(i+extension_factor)%precision] - f.exp(p_evaluations[i], 3) - constants_mini_extension[i % len(constants_mini_extension)]) % molus for i in range(precision)] print('Computed C(P, K) polynomial')
有个代数定理证明,如果Q(x)在所有这些x坐标,都等于零,那么最小多项式的乘积就会在所有这些x坐标等于零:Z(x) = (x – x_1) * (x – x_2) * … * (x – x_n)。通过证明在任何单个的坐标,Q(x)是等于零,我们想要证明这个很难,因为验证这样的证明比运行原始计算需要耗费更长的时间,我们会使用一个间接的方式来证明Q(x)是Z(x)的乘积。并且我们会怎么做呢?通过证明D(x) = Q(x) / Z(x),并且使用FRI来证明它其实是个多项式,而不是个分数。
我们选择低次单位根和高次单位根的特定排列,因为事实证明,计算Z(x),而且除以Z(x)也十分简单:Z 的表达式是两项的一部分。
需要注意地是,直接计算Z的分子和分母,然后使用批量模逆的方法将除以Z转换为乘法,随后通过 Z(X) 的逆来逐点乘以 Q(x) 的值。需要注意,对于低次单位根的幂,除了最后一个,都可以得到Z(x) = 0,所以这个计算包含其逆计算就会中断。这是非常不幸的,虽然我们会通过简单地修改随机检查和FRI算法来堵住这个漏洞,所以就算我们计算错误,也没关系。
因为Z(x)可以简洁地表达,我们也可以获得另个好处:验证者对于任何特别的x,可以快速计算Z(x),而且还不需要任何提前计算。对于证明者来说,我们可以接受证明者必须处理大小等于步数的多项式,但我们不想让验证者做同样的事情,因为我们希望验证过程足够简洁。
# Compute D(x) = Q(x) / Z(x) # Z(x) = (x^steps - 1) / (x - x_atlast_step) z_num_evaluations = [xs[(i * steps) % precision] - 1 for i in range(precision)] z_num_inv = f.multi_inv(z_num_evaluations) z_den_evaluations = [xs[i] - last_step_position for i in range(precision)] d_evaluations = [cp * zd * zni % molus for cp, zd, zni in zip(c_of_p_evaluations, z_den_evaluations, z_num_inv)] print('Computed D polynomial')
在几个随机点上,进行概念检测D(x) * Z(x) = Q(x),从而可以验证转账约束,每个计算步骤是之前步骤的有效结果。但是我们也想验证边界约束,其中计算的输入和输出就是证明者所说的那样。只是要求证明者提供P(1), D(1), P(last_step)还有D(last_step)的数值,这些都是很脆弱的;没有证明,那些数值都是在同个多项式。所以,我们使用类似的多项式除法技巧:
# Compute interpolant of ((1, input), (x_atlast_step, output)) interpolant = f.lagrange_interp_2([1, last_step_position], [inp, output]) i_evaluations = [f.eval_poly_at(interpolant, x) for x in xs] zeropoly2 = f.mul_polys([-1, 1], [-last_step_position, 1]) inv_z2_evaluations = f.multi_inv([f.eval_poly_at(quotient, x) for x in xs]) # B = (P - I) / Z2 b_evaluations = [((p - i) * invq) % molus for p, i, invq in zip(p_evaluations, i_evaluations, inv_z2_evaluations)] print('Computed B polynomial')
那么,我们的论证如下。证明者想要证明P(1) == input和P(last_step) == output。如果我们将I(x)作为插值,那么就是穿越(1, input)和(last_step, output)亮点的线,于是P(x) – I(x)就会在这亮点上等于零。因此,它会证明P(x) – I(x)是P(x) – I(x)的乘积,并且我们通过提高商数来证明这点。
紫色:计算轨迹多项式 (P) 。绿色:插值 (I)(注意插值是如何构造的,其在 x = 1 处等于输入(应该是计算轨迹的第一步),在 x=g^(steps-1) 处等于输出(应该是计算轨迹的最后一步)。红色:P-I。黄色:在x = 1和 x=g^(steps-1)(即 Z2)处等于 0 的最小多项式。粉红色:(P – I) / Z2。
现在,我们来看看将P,D和B的默克尔根部组合在一起。
现在,我们需要证明P,D和B其实都是多项式,并且是最大的正确阶数。但是FRI证明是很大且昂贵的,而且我们不想有三个FRI证明,所以,我们计算 P,D 和 B 的伪随机线性组合,并且基于它来进行FRI证明:
# Compute their Merkle roots mtree = merkelize([pval.to_bytes(32, 'big') + dval.to_bytes(32, 'big') + bval.to_bytes(32, 'big') for pval, dval, bval in zip(p_evaluations, d_evaluations, b_evaluations)]) print('Computed hash root')
除非所有这三个多项式有正确的低阶,不然几乎不可能有随机选择的线性组合,所以这很足够。
我们想要证明D的阶数小于2 * steps,而且P 和 B 的次数小于steps,所以我们其实使用了随机的P, P * xsteps, B, Bsteps 和 D的随机组合,并且可以看出这部分组合是小于2 * steps。
现在,我们来检查下所有的多项式组合。我们先获得很多随机的索引,然后在这些索引上为默克尔树枝提供多项式:
k1 = int.from_bytes(blake(mtree[1] + b'\x01'), 'big') k2 = int.from_bytes(blake(mtree[1] + b'\x02'), 'big') k3 = int.from_bytes(blake(mtree[1] + b'\x03'), 'big') k4 = int.from_bytes(blake(mtree[1] + b'\x04'), 'big') # Compute the linear combination. We don't even bother calculating it # in coefficient form; we just compute the evaluations root_of_unity_to_the_steps = f.exp(root_of_unity, steps) powers = [1] for i in range(1, precision): powers.append(powers[-1] * root_of_unity_to_the_steps % molus) l_evaluations = [(d_evaluations[i] + p_evaluations[i] * k1 + p_evaluations[i] * k2 * powers[i] + b_evaluations[i] * k3 + b_evaluations[i] * powers[i] * k4) % molus for i in range(precision)]
get_pseudorandom_indices函数会回复[0…precision-1]范围中的随机索引,而且exclude_multiples_of参数并不会给出特定参数倍数的值。这就保证了,我们不会沿着原始计算轨迹进行采样,否则就会获得错误的答案。
证明是由一组默克尔根、经过抽查的分支以及随机线性组合的低次证明组成:
# Do some spot checks of the Merkle tree at pseudo-random coordinates, excluding # multiples of `extension_factor` branches = [] samples = spot_check_security_factor positions = get_pseudorandom_indices(l_mtree[1], precision, samples, exclude_multiples_of=extension_factor) for pos in positions: branches.append(mk_branch(mtree, pos)) branches.append(mk_branch(mtree, (pos + skips) % precision)) branches.append(mk_branch(l_mtree, pos)) print('Computed %d spot checks' % samples)
整个证明最长的部分是默克尔树分支,还有FRI证明,这是有更多分支来组成的。这是验证者的实质结果:
o = [mtree[1], l_mtree[1], branches, prove_low_degree(l_evaluations, root_of_unity, steps * 2, molus, exclude_multiples_of=extension_factor)]
在每个位置,证明者需要提供一个默克尔证明,从而让验证者能够检查这个默克尔证明,并且检查C(P(x), P(g1*x), K(x)) = Z(x) * D(x)以及B(x) * Z2(x) + I(x) = P(x)(提醒:对于不在初始计算轨道上的x,Z(x)不会是零,所以C(P(x), P(g1*x), K(x)也不会是零)。验证者也会检查线性组合是正确的,然后调用。
for i, pos in enumerate(positions): x = f.exp(G2, pos) x_to_the_steps = f.exp(x, steps) mbranch1 = verify_branch(m_root, pos, branches[i*3]) mbranch2 = verify_branch(m_root, (pos+skips)%precision, branches[i*3+1]) l_of_x = verify_branch(l_root, pos, branches[i*3 + 2], output_as_int=True) p_of_x = int.from_bytes(mbranch1[:32], 'big') p_of_g1x = int.from_bytes(mbranch2[:32], 'big') d_of_x = int.from_bytes(mbranch1[32:64], 'big') b_of_x = int.from_bytes(mbranch1[64:], 'big') zvalue = f.div(f.exp(x, steps) - 1, x - last_step_position) k_of_x = f.eval_poly_at(constants_mini_polynomial, f.exp(x, skips2)) # Check transition constraints Q(x) = Z(x) * D(x) assert (p_of_g1x - p_of_x ** 3 - k_of_x - zvalue * d_of_x) % molus == 0 # Check boundary constraints B(x) * Z2(x) + I(x) = P(x) interpolant = f.lagrange_interp_2([1, last_step_position], [inp, output]) zeropoly2 = f.mul_polys([-1, 1], [-last_step_position, 1]) assert (p_of_x - b_of_x * f.eval_poly_at(zeropoly2, x) - f.eval_poly_at(interpolant, x)) % molus == 0 # Check correctness of the linear combination assert (l_of_x - d_of_x - k1 * p_of_x - k2 * p_of_x * x_to_the_steps - k3 * b_of_x - k4 * b_of_x * x_to_the_steps) % molus == 0
其实还没有完成成功;证明对跨多项式检查和 FRI 所需的抽查次数的可靠性分析是非常棘手的。但是这些就是所有代码,至少你不用担心进行疯狂的优化。当我运行以上代码的时候,我们会获得STARK证明,会有300-400倍的证明成本例如,一个需要 0.2 秒的 MIMC 计算需要 60 秒来证明)。这就使得4核机器计算MIMC中的 STARK,实际上可以比后向计算 MIMC 更快。也就是说,在python语言,这会相对低效的实现,并且这也会证明运行时间比例会不同。同时,也值得指出,MIMC 的 STARK 证明成本非常低,因为MIMC几乎是完美地可计算,它的数学形式很简单。对于平均计算,会包含更少的清晰计算(例如,检查一个数是大于还是小于另一个),其计算成本可能会更高,会有大约10000-50000倍。

阅读全文

与半隐式法python相关的资料

热点内容
斐波那契数列矩阵算法 浏览:674
公式保护后加密不了 浏览:82
java跳转到jsp 浏览:819
327平方根算法 浏览:216
win7美化命令行终端 浏览:797
免加密狗图片 浏览:485
一只透明的鸟是什么app 浏览:817
空气压缩机油批发商 浏览:69
linuxifexist 浏览:4
加密tf卡拷入文件 浏览:399
山西php工资 浏览:673
福州看病预约用什么小程序app 浏览:238
php保留两位小数不四舍五入 浏览:292
黑马程序员路径大全 浏览:1000
saas平台PHP 浏览:333
云服务器科学计算配置怎么选 浏览:649
jar解压命令 浏览:609
php正则问号 浏览:299
无线已加密不可上网是怎么了 浏览:465
什么app可以免费做手机 浏览:376