阅读《Lua程序设计(第4版)》---3

总结

精简模式:在标准Lua下,整型是64位大小,浮点数是双精度的。在资源有限的平台下,可以通过宏 LUA_32BITS 编译出精简Lua ,精简模式下整型大小是32位,浮点数是单精度。

数值常量:表示数值常量时,小数点前后的内容都是可选的;如 3.3  .133  67.  都是正确的。
                  数值当然也可以用指数形式表示,如4E+20   .5e12  等前面的小数部分和之前相同,小数点前后内容都是可选的,指数部分必须是一个整数,不能是小数, e 和 E 都是可以的。
                  也可以在开头加 0x 或 0X 来表示十六进制,Lua 同样支持 C99 中的十六进制浮点数,由小数部分和以 p 或 P 开头的指数部分组成,十六进制小数虽然可读性很差,但是它的运算是精准的且格式输出时转换速度更快。

C99 里16进制浮点数记数法:类似E,但不同。数以0x开头(数字0字母x),然后是16进制浮点数部分,接着是p,后面是以 2为底的阶码。
例如:0xb.1ep5 其中:
b.1e 是16进制浮点数, 乘后面的p5。p5 等于 2的5次方(10进制512)。
所以化成十进制:(11+1/16.0+14/256.0) * 512.0。

1.type和math.type

math.type函数:存在小数部分或者用指数形式表示的数值都认为是浮点型值,否则认为是整型。Lua标准库中的 math.type 函数会返回数值的类型(一个字符串),float 或 integer

type函数:返回数值的基本数据类型(一个字符串)

print(type(3.0))
print(type(3))
print("=====")
print(math.type(3.0))
print(math.type(3))

2.16进制浮点数记数法

print(0x1p-1) ---1*2^-1
print(0xa.bp2)---(10+0.6875)*2^2
print(string.format("%a",419))
print(string.format("%a",0.1))

3.算术运算

两个整型运算结果是整型,两个浮点型运算结果是浮点型,一个整型一个浮点型时先将整型值转换为浮点型然后运算。

Lua 中整除( // )的结果会向负无穷取整,取余( % )运算的定义是 a % b== a - (( a // b) * b ),因此取模结果的符号和操作数 b 相同,这与C类语言中的取模运算大不相同,因为整除的结果是向负无穷取整,而不是向零取整。

浮点数也可以进行取余和整除运算。
除法和指数运算的结果必然是浮点数,因此会将两个操作数都转化为浮点数后再进行运算。

--[[
算术运算前先将整形值转换成浮点型,再运算
除法/、^永远是浮点数
floor除法 无穷取整数
]]
print(3/2)
print(3//2)
print(3.0//2)
--[[
%定义:a % b = a - ((a//b)*b)
]]
x = math.pi
print(x-x%0.01)
print(x-x%0.001)

4.关系运算

关系运算符有 > < <= >= == ~= ,关系运算的结果都是 boolean 类型,比较数值时相同子类型运算效率会更高。

5.位运算

Lua 中的位运算功能和 C 语言中的完全一致;

异或的运算符号有所不同,Lua 语言中的异或运算符是 ~ ,和按位取反的符号相同;

位运算只能对整型数使用,因此运算前会试图将两个操作数都转化为整型,如果转换失败(小数部分不为 0 ),会立即引发错误。

6.运算精度

标准 Lua 下整型最大值为 2^63 - 1,最小值为 -2^63 ,整型数的运算都是精确且可以预测的;

而双精度浮点数能精确表示的整数范围被限制在 [ -2^53 , 2^53 ] 之间,超出这个范围后多出的位数不再存储,因此浮点数的运算必须要考虑精度损失的问题。

--[[
表示范围
浮点数表示整数范围被精确地限制在[-2^53,2^53],2^53数值9007 1992 5474 0992
]]
print("\n")
print(math.maxinteger + 1 == math.mininteger)
print(math.mininteger - 1 == math.maxinteger)
print(- math.mininteger ==  math.mininteger)
print(math.mininteger // -1 == math.mininteger)

print(math.maxinteger)
print(0x7fffffffffffffff)
print(math.mininteger)
print(0x8000000000000000)

print(math.maxinteger + 2)
print(math.maxinteger + 2.0)

print(math.maxinteger + 2.0 == math.maxinteger + 1.0)


--[[
惯例
]]
print("\n")
-- 整型强制转换成浮点型
print(-3+0.0) 
print(0x7fffffffffffffff+0.0)
--精度对比
print(2^53)
print(9007199254740991 + 0.0 == 9007199254740991)
print(9007199254740992 + 0.0 == 9007199254740992)
print(9007199254740993 + 0.0 == 9007199254740993)
--浮点型强制转换成整数型
print(2^53)
print(2^53 | 0)

--print(3.2 | 0) --error : number has no integer representatiion 存在小数部分
--print(2^64 | 0)  --error: number has no integer representatiion 超出范围
--print(math.random(1,3.5)) -- bad argument #2 to ‘random’ (数值没有用整形表示)

print(math.tointeger(-258.0))
print(math.tointeger(2^30))
print(math.tointeger(5.01)) --不是整数值
print(math.tointeger(2^64)) --超出范围

function cond2int(x)
    -- do somethings
    return math.tointeger(x) or  x
end

print(cond2int(-258.0))
print(cond2int(2^30))
print(cond2int(5.01)) --不是整数值
print(cond2int(2^64)) --超出范围



print("\n")

7.运算符优先级

--[[
运算符优先级(^ 从右到左结合,其他从左到右结合)
^  
一元运算符(- ~ # not)
* / // %
+ -
..   (链接)
<< >> (按位位移)
 &   (按位与)
~    (按位异或)
|    (按位或)
< > <= >= == ~=
and 
or
]]
---位运算只能对整型数使用
---Lua 语言中的异或运算符是 ~ ,和按位取反的符号相同。位运算只能对整型数使用,因此运算前会试图将两个操作数都转化为整型,如果转换失败(小数部分不为 0 ),会立即引发错误
--[[
指数运算是从右到左
]]
print(2^3^4)
print(2^-3^4)

8.数学库

 Lua 标准库中有标准数学库 math ,包含了一组常用数学函数。

              math.tointeger                                 浮点类型转整型,不成功则返回 nil

              math.type                                        返回数值类型的子类型,不是数值类型则返回 nil

              math.abs   math.sqrt                       绝对值/开方(Lua中用处不大,开方可以直接 x^0.5 )

              math.sin  math.cos  math.tan          正弦/余弦/正切

              math.asin  math.acos  math.atan    反正弦/反余弦/反正切

              math.ceil   math.floor   math.modf   向上取整/向下取整/得到整数和小数部分

              math.exp                                         计算 e^x

              math.rad   math.deg                        度数转弧度/弧度转度数

              math.fmod                                       C语言中的取余(整除是向零取整)

              math.log                                          对数运算,默认底数是 e

              math.max   math.min                      若干个数的最大值/最小值

              math.ult                                           把两个参数当作无符号数运算,当第一个参数小于第二个时返回true(整型参量)

             math.random   math.randomseed    产生随机数,默认产生[ 0,1 )的浮点数,还可以给定两个整型参数,返回[ x,y ]之间的整型随机数/重置随机数种子

             标准数学库中的常量

             math.huge                                        C语言math.h中的HUGE_VAL,无穷大

             math.maxinteger   math.mininteger 整型数的最大值/最小值

             math.pi                                             Pi 值

 

--[[
math -->三角函数 弧度制,deg和rad角度和弧度转换
huge -->最大可表表示数值,在大多数平台上表示Inf
]]
print(math.rad(30))
print(math.deg(math.pi/6))

print(math.sin(math.pi/6))
print(math.sin(math.rad(30)))
print("--------------")
--[[
生成伪随机数
math.random()    -->[0,1)
math.random(6)   -->[1,6]
math.random(1.4) -->[1,4] 
math.randomseed()  -->默认为1,每次程序运行都会生成相同的伪随机数序列,一般math.randomseed(os.time())
]]
math.randomseed(os.time())--执行/取消
print(math.random())
print(math.random(6))
print(math.random(1,3))
print("--------------")
--[[
取整函数 floor 、ceil、modf,分别为向负无穷取整,向正无穷取整、向零取整(返回整数+小数部分)
]]
print("\n")
print(math.floor(3.3))
print(math.floor(-3.3))
print(math.ceil(3.3))
print(math.ceil(-3.3))
print(math.modf(3.3))
print(math.modf(-3.3))
print("--------------")
print(math.floor(2^70))
x = 2^52 + 1
print(string.format("%d %d",x,math.floor(x+0.5)))
function round(x)
    -- do somethings
    local f = math.floor(x)
    if x == f then return f
    else return math.floor(x+0.5)
    end
end

print(string.format("%d %d",x,round(x+0.5)))

--[[
无偏取整-->向距离最近的偶数取整半个整数
]]

function round2(x)
    -- do somethings
    local f = math.floor(x)
    if(x == f) or (x % 2.0 == 0.5) then
        return f
    else
        return math.floor(x+0.5)
    end
end

print(round2(2.5))
print(round2(3.5))
print(round2(-2.5))
print(round2(-3.5))
print(round2(-1.5))

练习3.1

---练习3.1 以下哪些值是有效的数值常量?它们的值分别是多少?
-- .0e12       有效  0.0
-- .e12        无效  '.' unexpected
-- 0.0e        无效  malformed number near '0.0e'
-- 0x12        有效  18
-- 0xABFG      无效  syntax error
-- 0xA         有效  10
-- FFFF        无效  变量名
-- 0xFFFFFFFF  有效  4294967295
-- 0x          无效  syntax error
-- 0x1P10      有效  1024.0
-- 0.1e1       有效  1.0
-- 0x0.1p1     有效  0.125

print(.0e12) 
--print(.e12) 
print(0x12)
print(0xA)
print(0xFFFFFFFF)
print(0x1P10)
print(0.1e1)
print(0x0.1p1)

练习3.2

---练习3.2 解释下列表达式之所以得出相应结果的原因。(注意:整型算术运算总是会回环)
print(math.maxinteger * 2)               -- => maxinteger +  (maxinteger + 1) - 1 => maxinteger + mininteger - 1 =>  -1 + -1 => -2
print(math.mininteger * 2)               -- => mininteger +  (mininteger - 1) + 1 => mininteger + maxinteger + 1 =>  -1 +  1 => 0
print(math.maxinteger * math.maxinteger) -- => maxinteger * (mininteger - 1) => mininteger - maxinteger => 1
print(math.mininteger * math.mininteger) -- => mininteger * (maxinteger + 1) => mininteger + mininteger => 0
--[[
1. 乘2相当于左移1位,0111…1111左移1位后变为1111…1110,对应的原码值就是 -2
2. 1000…0000左移1位后变为 0000…0000,对应的原码值就是 0
3. 0111…1111 * 0111…1111 除最低位是1不变,其他位均发生进位后为 0(每高一位1的个数加1,进位得到的1也加一,一直保持偶数个1)
4. 最高位发生进位后,所有位都是 0
]]

 

练习3.3

---练习3.3 下列代码的输出结果是什么?
for i = -10, 10 do
    print(i , i % 3)
end
-- 太长就不贴出来了 运行下即可
-- 注意 : Lua的取整除法向负无穷取整
      -- 比如 -10 // 3 等于 -4 而不是 -3
      -- 所以 -10 % 3 等于 2 而不是 -1
      --若要得到与C++等语言一样的结果请使用 math.fmod
--[[
floor为向负无穷取整
%

可以看出Lua 中向下取余的特性在正数时与C类语言中向零取余的结果是一样的,但在负数时Lua取余也是向下取整后加上余数等于被除数,C类语言中取余变为向上取整后加上余数等于被除数。
]]

练习3.4

---练习3.4 表达式2^3^4的值是什么?表达式2^-3^4呢?
print(2^3^4)   -- 2.4178516392293e+024
print(2^-3^4)  -- 4.1359030627651e-025

练习3.5

--[[
12.7可以表示成以10为底的幂作为分母的分数,你能把12.7表示为以2为底的幂作为分母的分数吗?再试试5.5?

只需找到一个 2^n * 12.7 结果是一个整数,Lua中有两个简便的方法。

1.得到的结果对1取余,结果是0,因为Lua的浮点数也是可以取余哒,就很方便。

2.使用math.tointeger函数,如果不能转整型,函数会返回 nil ,这个特性也可以轻松判断是否是整数。
————————————————

]]
function   exercise3_5(num)
    -- do somethings
    local base,sp,cnt = 1,num,0  ---Lua的赋值
    while math.tointeger(sp) == nil do
        base = base *2
        cnt = cnt + 1
        if cnt == 63 then
            print("Huge Number,Can Not Solve!\n")
            return  
        end
        sp = num * base
    end
    
    sp = math.tointeger(sp)
    print("Got It,2^"..cnt)
    print(sp.."/"..base.."="..(sp/base))
end

exercise3_5(12.7)
print("\n")
exercise3_5(5.5)

print("------------------------")

练习3.6

function exercise3_6(h,p)---高度和角度
    return 1.0/3.0*((math.tan(math.rad(p))*h)^2.0*math.pi)*h
end

print("------------------------")

练习3.7

function exercise3_7()
    local rand1,rand2 = math.random(),math.random()
    rand1 = (rand1 == 0) and (1) or rand1
    rand2 = (rand2 == 0) and (1) or rand2
    return math.sqrt(-2.0*math.log(rand1))*math.sin(2*math.pi*rand2)
end

tabexercise3_7 = {}
math.randomseed(os.time())
for i=1,10000000  do
    local  sp= exercise3_7()
    sp = (sp+0.05)//0.1
    if tabexercise3_7[sp] == nil then
        tabexercise3_7[sp] = 1
    else
        tabexercise3_7[sp] = tabexercise3_7[sp]+1
    end
end
for i=-100,100,1 do
    if tabexercise3_7[i] ~= nil then
        print(i,tabexercise3_7[i])
    end
end

 

posted @ 2021-07-24 16:04  微臣做不到  阅读(554)  评论(0编辑  收藏  举报