应该是编译 Ruby 时就决定好是用 berkleydb 或者 gnu dbm 了,看 DBM::VERSION
可以知道是哪种。如果系统两种都有,可以在安装时加 --with-dbm-type
指定,参见 ruby 源码目录/ext/dbm/extconf.rb
楼主,你转载获得作者同意了吗?或者你就是作者?
我也不用 raw 和 html_safe, 我直接用 <%==
......
#12 楼 @zhufenggood pry 已经内建了:edit Sinatra.new.get
cache line 魔法... 5qword -> 8qword 速度有 6% 的轻微提升,但是平均多 25% 的内存消耗,最差情况会多耗 60% 内存,很可能还要调整... 估计最后会改成 6qword 的方案 (速度 +3%, 目测内存消耗 +5%)
#13 楼 @michalyang 或者找个人拷一下...
#10 楼 @michalyang 说明 /usr/bin 不在路径内,/usr/bin/sudo 应该有的 (bash 不是 cmd, 你要 ./sudo
), 没有就重装系统吧...
这些目录都存在吗?怀疑是没装 xcode 所以不存在。
/usr/local/bin /usr/local/lib /usr/local/share /usr/local/share/man /usr/local/share/man/man1 /usr/local/share/man/man3 /usr/local/share/man/man5 /usr/local/share/man/man7
少的目录都补上应该就好了
require 'scanf'
'1 2 3 4'.scanf '%d %d %d %d'
brew 加个 -v 参数看看卡在哪里 brew install -v libtiff
浮点数的计算机表示,大一就应该学过吧...
另外有效数字多的才比较精确,所以 0.16000000000000003 比 0.16 精确才对。楼主想要的其实并不是精确结果,而是适合阅读和记诵的结果。
% 占位符,和 C 语言一致:
"name:%s,age:%d" % ["sx", 23]
推荐写法:
"name:#{"sx"},age:#{23}"
345.363631248474*1024*1024 的结果明显不该是整数啊...
小学生都能告诉你,用 bigdecimal 算出来的结果是精确的,你看 345.363631248474 带了 12 位小数,而最末位不是 5, 那不管乘以 1024 多少次,运算结果还是必须至少带 12 位小数且最后不是 0. 另外用 ruby 2.0 的有理数 (注意 r 后缀) 也显示分数不可约:
345.363631248474r * 1024 * 1024 #=> (88413089599609344/244140625)
其实 excel 也是用双精度浮点数,唯一区别就是,它取 64bit 时用了进位,而 ruby 取 64bit 时和其他编程语言一样用了截断。
我们可以做个实验,把 345.363631248474 用 80 bit 浮点数 (long double) 表示,然后看看每个字节
#include <stdio.h>
typedef union {
long double ieee754;
unsigned char binary[10];
} Converter;
int main (int argc, char const *argv[]) {
long double n = 345.363631248474L;
Converter c;
c.ieee754 = n;
// 看看每个字节
printf("%s", "bytes: ");
for (long i = 0; i < 10; i++) {
printf("%d,", c.binary[i]);
}
printf("%s", "\n");
// 四舍五入把低 16 位置 0
c.binary[0] = 0;
c.binary[1] = 0;
c.binary[2] = 0;
c.binary[3] = 0;
c.binary[4] ++;
printf("before: %.20Lf\n", n * 1024 * 1024);
printf("after: %.20Lf\n", c.ieee754 * 1024 * 1024);
return 0;
}
结果
bytes: 245,238,255,255,119,139,174,172,7,64,
before: 362140014.99999987301998771727
after: 362140015.00000000000000000000
另外注意 ruby 里的 to_i
是截断 (在 C 里用 (int)
强转浮点数到整数也是截断的,least surprise 原则), round
才是四舍五入的。
卡西欧也是用双精度浮点数,算下面这样的数结果一样是 0:
1E60 + 1 - 1E60
ruby bigdecimal 可以算出正确结果 1:
BigDecimal('1E60') + 1 - BigDecimal('1E60')
视频说的不是模运算啊,而是 N/12 上的加法 而且说的那个是含幺半群 Monoid, 定义和 Monad 很相近但不是 Monad.
/
(\d*.)? # 可选组
\d{1,3} # 1到3个数字
-? # 最后的减号也是可选的
/x
所以还是 rbenv 这种 magic 比较少的好...
#16 楼 @jiyinyiyong 编译器和解释器代码构造相似,真正干事情的地方改成打印或者拼字符串就可以了。你可以先弄个输出 js/C 代码的编译器,会玩了就可以尝试输出 llvm 字节码了 (如果用 llvm 的话,建议实现语言选 C++, 可以少走很多弯路). 想直接输出 x86 也不难,可以看看 libjit 和 xbyak, 不过要先学习 calling convention 和熟悉 stack layout.
.NET DLR 上做语言更简单,把树给它就好了。
关键词都给你了,自己看 wiki 咯。
#4 楼 @jiyinyiyong 编译到二进制很简单的,把 vm 指令都改成函数调用就可以了,其实和解释执行区别不大... 如果把 vm 指令的实现内联进来,就能省掉 call 的开销,但编译出来的结果就会很大 (这里很矛盾的,如果用提取公共子表达式之类的优化手段,就退化回前面那种代码了). 所以一般都选择性的内联,和选择性的优化 (编译时间比执行时间还长的话,即时编译也没有意义了)
编译期类型作用就是去掉运行时的类型检查和方法查找开销,如果调用目标代码固定了就能内联进来 -- 但动态语言就是不固定的,很多脚本的大部分代码就是只运行一遍,延迟到运行时检查速度更快。还有个作用是利用数据类型的知识,减少从 tagged pointer 拆箱/装箱的开销,减少从对象取成员/写成员的开销 -- 但是这种优化之前往往要做逃逸分析,对象逃不出去才能这么做,而只要语言支持 continuation 或者比较强的运行时反射,基本都逃逸了... 另外,声明成 immutable 的变量就可以不用做逃逸分析直接拆箱。