浮点避坑

浮点数相加

我们知道浮点数尽量避免不同量纲的数相加

1
2
> 1023 + 0.00000000000001
Double = 1023.0

浮点数除法

不同量纲之间的除法也会得到不一样的结果

1
2
3
4
> 1.023/2.047
Double = 0.49975574010747426
> 1023.0/2047.0
Double = 0.49975574010747437

因此对于有些应用可能引入意向不到的结果
比如

1
2
3
4
> 1023.0/2047.0*2.047 == 1.023
Boolean = false
> 1023.0/2047.0*2047 == 1023
Boolean = true

避免不同量纲的数做加减法,还要注意不同量纲的数做乘除法带来的意外结果

典型的例子

1
2
3
0.3 - 0.1
floor( 0.3*10 - 0.1 *10 ) //2.0
floor((0.3 - 0.1)*10 ) //1.0

Double Eps 精度

1
2
Float  (B=2 / p=24): Eps = 2^(-24) = 5.9604644775390625E-8
Double (B=2 / p=53): Eps = 2^(-53) = 1.1102230246251565E-16

也就是说计算机能表示的最小绝对值

1
2
0+1E-16 = E-16
1+1E-16 = 1.0

他的精度跟指数位有关,总共E-16次方的误差范围,指数位占n位,那么误差就等与E(-16+n)

1
2
3
4
1000+1e-16= 1000.0
1000+1e-15= 1000.0
1000+1e-14= 1000.0
1000+1e-13= 1000.0000000000001

只要指数位和分数位之和不要超过16,都可以表示

1
2
3
4
5
6
7
1E10+1E-6 = 1.0000000000000002E10   //能表示1E-6不能表示

1E10+1E-7 = 1.0E10 //误差1E-7不能表示
1E8+1E-7 = 1.000000000000001E8 //指数位8,误差1E-7可以表示
1000000 +1E-10 = 100000.0000000001 //可以表示1E-10
10000000 +1E-10 = 10000000.0 //不能表示1E-10误差,指数位占了7
1E18 + 13 = 1e18

所以你在用浮点计算的时候,要看数的量纲,量纲越大,Eps要设置的大一些, 否则就失去了意义

Scala EPS

所以在判断一个数是否为0是, 不能 a == 0 而是要 abs(a) <= Eps ,
同样在比较两个数是否相等时,不能 a == b 而是要 abs(a - b) <= Eps

BigDecimal

Double的问题是精度有限

1
2
3
val a = 0.02
val b = 0.03
val c = b - a

c的结果不是0.01,而是c: Double = 0.009999999999999998
因此有些系统设计中不能用double,不如金融银行金额计算
为什么会这样呢? 因为float和double都是浮点数, 都有取值范围, 都有精度范围. 浮点数与通常使用的小数不同, 使用中, 往往难以确定.
常见的问题是定义了一个浮点数, 经过一系列的计算, 它本来应该等于某个确定值, 但实际上并不是!
double相减会转换成二进制,因double有效位数为 16位这就会出现存储小数位数不够的情况,这种情况下就会出现误差,解决方法就是使用BigDecimal,它的有效长度足够长可存储小数位数。
因此可代替double来进行加减乘除, 金额必须是完全精确的计算, 故不能使用double或者float, 而应该采用java.math.BigDecimal.

1
2
3
val a = BigDecimal(0.02)
val b = BigDecimal(0.03)
val c = b - a

c的结果得到0.01

1
2
3
val a =  BigInt("1234567890123456").toLong
val b = 0.001
val c = a + b

c的值为1234567890123456,0.01丢失

1
2
3
val a =  BigDecimal("1234567890123456")
val b = BigDecimal(0.001)
val c = a + b

c的值为1234567890123456.001,精度并不会丢失

BigDecimal(value), value可以用数字初始化,太大的值只能用字符串初始化如“123456789012345678”

1
2
3
4
5
6
7
val a =  BigDecimal("1234567890123456001")
val b = BigDecimal(0.1231)
val c = a * b
c.precision
c.rounded
c.scale
c.pow(2)
1
2
3
val c= BigDecimal("1234.5000")
c.doubleValue
c.round(new java.math.MathContext(4, java.math.RoundingMode.HALF_UP))

slides(revealjs 导出PDF)

1. export HTML to slides

$: unzip reveal.js.master.zip
$: cd reveal.js.master

2. Edit index.html

Export to reveal.js from https://slides.com/yourname/yourslide/edit
Presentation made with Slides are powered by the reveal.js open source presentation framework. This export lets you migrate your slide content to a fresh reveal.js install.
a. Download a copy of the reveal.js framework and make the following edits to its index.html.
b. In the , replace the theme CSS with:
c. In the , replace the

node with:
d. In the Reveal.initialize call towards the bottom of your index.html, append these config values:

3. Edit index pdf config

a. edit index.html
add. Reveal.Configure before Reveal.initialize

1
2
3
Reveal.configure({ pdfSeparateFragments: false,
pdfMaxPagesPerSlide: 1 });
Reveal.initialize({ ...

4. Export pdf

open index.html by Chrome like http://xxxx.index.html?print-pdf
Ctrl-P(windows) or COMMAND-P(Mac-OS)
Save

FAQ

  1. Save Fail(Preview Failure)
    print range - full
    I found Chrome export pdf raise Error when pages number bigger than 56
    So you should export it twice 1-56, 57~64

博文收藏

博客收藏

函数式编程

什么是函数式编程
函数式代码是对“映射的描述”,输入x和输出y的映射关系 y=f(x)
函数式编程在 描述是什么
命令式编程在 应该怎样做

其他

Hexo 技巧收录

草稿功能

草稿相当于很多博客都有的“私密文章”功能。

1
$ hexo new draft "new draft"

会在source/_drafts目录下生成一个new-draft.md文件。但是这个文件不被显示在页面上,链接也访问不到。也就是说如果你想把某一篇文章移除显示,又不舍得删除,可以把它移动到_drafts目录之中。
如果你希望强行预览草稿,更改配置文件:

1
render_drafts: true

或者,如下方式启动server:

1
$ hexo server --drafts

下面这条命令可以把草稿变成文章,或者页面:

1
$ hexo publish [layout] <filename>

综合时序分析回顾

关于计算机大小端

一般计算机所讲的大小端指的是字节序的大小端,比特序一般默认都是小端无论字节序为大端还是小端

字节序大小端

HSB(大端格式):
按字节从大到小排布

1
2
3
byte0,byte1,byte2,byte3
byte4,byte5,byte6,byte7
...

LSB(小端格式):
按字节从小到大排布

1
2
3
byte3,byte2,byte1,byte0
byte7,byte6,byte5,byte4
...

比特序大小端

bit大端 =[01234567]
bit小端 =[76543210]
一般常见的都是bit小端

Terminal配置常见问题

Teriminal 配置常见问题

    1. ls后文件名包含引号,例如 'Program file'

      在 ~/.zshrc 里面配置

    1. MACOS ls 目录后没有颜色显示,

      'alias ls =/bin/ls -G' , 一定要指到/bin/ls

    1. 其他

晶振,PLL, VCO介绍

晶振,vco区别

晶振分有源晶振和无源晶振,一般会产生1~200Mhz时钟频率
vco亚控振荡器,可以产生比较高的频率比如2Ghz,但是不稳定

为什么既要晶振还要vco?

就是为了能够产生稳定的高频时钟信号,就需要用到PLL, PLL内部会有
一个VCO 产生高频时钟,通过分频器假设得到10分频的时钟2,再拿这个时钟2
和晶振产生的100mhz基用鉴相器做比较,输出一个比较的波形后经过低通滤波,
用输出电压控制VCO的输出, 那么就能是vco输出的高频时钟得到稳定的频率,达到了
倍频的效果。

20Mhz一下的晶振基本上都是基频的器件,稳定度好,20mhz以上的晶振大多是谐波(如3次,5次谐波)
稳定度差,因此强烈建议使用低频的器件,毕竟倍频器用的pll电路需要的周边配置主要是电容,
电阻,电感,其稳定度和价格方面要远远浩宇晶体晶振器件。

如果只需要一个20mhz以内的时钟频率,完全可以不用pll,直接接晶振就够了

晶振一般有哪些参数

晶振有几个重要参数:

1,晶体元件规格书中所指定的频率,也是工程师在电路设计和元件选购时首要关注的参数。晶振常用标称频率在1~200MHz之间,比如32768Hz、8MHz、12MHz、24MHz、125MHz等,更高的输出频率也常用PLL(锁相环)将低频进行倍频至1GHz以上。我们称之为标称频率。

2,输出信号的频率不可避免会有一定的偏差,我们用频率误差(Frequency Tolerance)或频率稳定度(Frequency Stability),用单位ppm来表示,即百万分之一(parts per million)(1/106),是相对标称频率的变化量,此值越小表示精度越高。比如,12MHz晶振偏差为±20ppm,表示它的频率偏差为12×20Hz=±240Hz,即频率范围是(11999760~12000240Hz)

3,还有一个温度频差(Frequency Stability vs Temp)表示在特定温度范围内,工作频率相对于基准温度时工作频率的允许偏离,它的单位也是ppm。

4,另外,负载电容CL(Load capacitance),它是电路中跨接晶体两端的总的有效电容(不是晶振外接的匹配电容),主要影响负载谐振频率和等效负载谐振电阻,与晶体一起决定振荡器电路的工作频率,通过调整负载电容,就可以将振荡器的工作频率微调到标称值。更准确而言,无源晶体的负载电容是一项非常重要的参数,因为无源晶体属于被动元器件,所谓的被动元器件即是自身不能工作,需要外部元器件协助工作,无源晶体即是!

其中:

CS为晶体两个管脚之间的寄生电容(又名晶振静态电容或Shunt Capacitance),在晶体的规格书上可以找到具体值,一般0.2pF~8pF不等。如图二是某32.768KHz的电气参数,其寄生电容典型值是0.85pF(在表格中采用的是Co)。

CG指的是晶体振荡电路输入管脚到GND的总电容,其容值为以下三个部分的和。

  • 需加外晶振主芯片管脚芯到GND的寄生电容 Ci
  • 晶体震荡电路PCB走线到到GND的寄生电容CPCB
  • 电路上外增加的并联到GND的外匹配电容 CL1
    CD指的是晶体振荡电路输入管脚到GND的总电容。容值为以下三个部分的和。
  • 需加外晶振主芯片管脚芯到GND的寄生电容, Co
  • 晶体震荡电路PCB走线到到gnd的寄生电容,CPCB
  • 电路上外增加的并联到GND的外匹配电容, CL2

既然晶振的负载电容是一个非常重要的参数,如果此项参数与外部电容匹配不正确会导致什么样的现象?晶振两端的等效电容与晶振标称的负载电容匹配不正确,晶振输出的谐振频率将与标称工作的工作频率会产生一定偏差(又称之为频偏),负载电容(load capacitance)主要影响负载谐振频率和等效负载谐振电阻,它与石英谐振器一起决定振荡器的工作频率,通过调整负载电容,一般可以将振荡器的工作频率调到标称值。应用时我们一般外接电容,便是为了使晶振两端的等效电容等于或接近负载电容,对于要求高的场合还要考虑ic输入端的对地电容,这样便可以使得晶振工作的频率达到标称频率。所以合理匹配合适的外加电容使晶振两端的等效电容等于或接近负载电容显得十分重要。

负载电容常用的标准值有12.5 pF,16 pF,20 pF,30pF,负载电容和谐振频率之间的关系不是线性的,负载电容变小时,频率偏差量变大;负载电容提高时,频率偏差减小。图3是一个晶体的负载电容和频率的误差的关系图。

例外情况:

现在有很多芯片内部已经增加了补偿电容(internal capacitance),所以在设计的时候,只需要选按照芯片datasheet推荐的负载电容值的选择晶体即可,不需要额外再加电容。但是因为实际设计的寄生电路的不确定性,最好还是预留CL1/CL2的位置。