在我的世界中实现一个数学库

gamersky_01small_02_2016926109e27
记分板/函数规范

同时为了开发者和使用者的方便,我在这里提供记分板命名规范。
记分板名称:<函数名>_<参数名>_<下标>
例子:abs_arg_0
函数名即是使用此记分板的函数的名称,参数名代表这个记分板的作用,下标在此参数名不止一个的时候防止冲突。
在此定死参数名类型:arg, out和tmp
※ arg即输入,out为输出,tmp是在计算过程中需要处理到的临时量。
在我们的规范中,输入的arg不会因计算改变。调用者只允许写入arg读取out,tmp不允许外部函数或者调用者操作。

我们的函数放置位置和命名也是有规范的

  • 所有函数必须存在于math命名空间内
  • math空间下存在函数的子目录,每个子目录内有与目录同名的.mcfunction文件。调用者调用这个文件。如果需要拆分function内容为多个文件的,皆放在相应函数的子目录下。例:math/functions/sqrt/sqrt.mcfunction调用math/functions/sqrt/iteration.mcfunction
  • 所需的记分板必须统一创造在math:init.mcfunction中,此function必须被load.json引用,且命名符合上述命名规范
  • 如果需要给函数功能分类,创建功能名子文件夹,并在文件夹下创建相应的函数文件夹

 


 

框架

 

目前我们实现了以下函数:

 

  1. - abs
  2. - pow
  3. - sqrt
  4. - vector:
  5.   - length
  6.   - normalize

复制代码

abs:

 

  描述:取绝对值

 

  参数:abs_arg_0 一个实数

 

  输出:abs_out_0 |abs_arg_0| 一个>=0的实数

 

pow:

 

  描述:求幂

 

  参数:pow_arg_0 底数,一个实数    pow_arg_1 指数,一个实数

 

  输出:pow_out_0 pow_arg_0的pow_arg_1次幂,一个实数

 

  注意:当指数为0时输出1,当指数<=0时输出0,而非1/n^m。主要是由于精度问题……

 

sqrt:

 

  描述:求平方根

 

  参数:sqrt_arg_0 被开方数,一个实数

 

  输出:sqrt_out_0 输入数的算术平方根*10^2,一个实数

 

  注意:输入为0时输出sqrt(abs(sqrt_arg_0))*10^2,输出sqrt(sqrt_arg_0)*10^2(精度所需)。为了保留精度在开始计算时会将输入*10^4。此值在                           init.mcfunction中以常量precision形式定义。必须满足precision=10^2n。默认为10^4,能求出4位数的平方根而不溢出。

 

vector/length:

 

  描述:计算三维向量的长度

 

  参数:leng_arg_0 输入向量的x    leng_arg_1 输入向量的y    leng_arg_2 输入向量的z

 

  输出:sqrt_out_0 输入向量的长度*10^2,一个实数

 

  注意:为了精度,此结果也被*10^2

 

vector/normalize

 

  描述:规格化三维向量

 

  参数:norm_arg_0 输入向量的x    norm_arg_1 输入向量的y    norm_arg_2 输入向量的z

 

  输出:norm_out_0 输出向量的x*10^2   norm_out_1 输出向量的y*10^2    norm_out_2 输出向量的z*10^2

 

  注意:为了精度,此结果为normalize(u)*10^2。并且因为精度,输出向量的长度并不严格为1

 


 

实现

 

我们将在这里阐述各个函数的实现

 

 

 

Initialization

 

init.mcfunction

 

  1. # Abs Start
  2. scoreboard objectives add abs_arg_0 dummy
  3. scoreboard objectives add abs_out_0 dummy
  4. # Abs End
  5. # Sqrt Start
  6. scoreboard objectives add sqrt_arg_0 dummy
  7. # Different
  8. scoreboard objectives add sqrt_tmp_0 dummy
  9. # Devide Result
  10. scoreboard objectives add sqrt_tmp_1 dummy
  11. scoreboard objectives add sqrt_out_0 dummy
  12. # Sqrt End
  13. # Pow Start
  14. # Base Number
  15. scoreboard objectives add pow_arg_0 dummy
  16. # Exponent
  17. scoreboard objectives add pow_arg_1 dummy
  18. # Counter
  19. scoreboard objectives add pow_tmp_0 dummy
  20. scoreboard objectives add pow_out_0 dummy
  21. # Pow End
  22. # Vector Start
  23. # Normalize Start
  24. scoreboard objectives add norm_arg_0 dummy
  25. scoreboard objectives add norm_arg_1 dummy
  26. scoreboard objectives add norm_arg_2 dummy
  27. scoreboard objectives add norm_out_0 dummy
  28. scoreboard objectives add norm_out_1 dummy
  29. scoreboard objectives add norm_out_2 dummy
  30. # Normalize End
  31. # Length Start
  32. scoreboard objectives add leng_arg_0 dummy
  33. scoreboard objectives add leng_arg_1 dummy
  34. scoreboard objectives add leng_arg_2 dummy
  35. scoreboard objectives add leng_out_0 dummy
  36. # Length End
  37. # Vector End
  38. # Constants Start
  39. scoreboard objectives add constants dummy
  40. scoreboard players set minus_one constants -1
  41. scoreboard players set zero constants 0
  42. scoreboard players set one constants 1
  43. scoreboard players set two constants 2
  44. scoreboard players set three constants 3
  45. scoreboard players set four constants 4
  46. scoreboard players set five constants 5
  47. scoreboard players set six constants 6
  48. scoreboard players set seven constants 7
  49. scoreboard players set eight constants 8
  50. scoreboard players set nine constants 9
  51. scoreboard players set ten constants 10
  52. # Precision 10^-4
  53. scoreboard players set precision constants 10000
  54. scoreboard players set pi constants 31415
  55. scoreboard players set e constants 27182
  56. scoreboard players set sqrt_out_prec constants 100
  57. scoreboard players set sqrt_diff constants 1
  58. # Constants End

复制代码

主要负责记分板的创建和设置各种常量……很乱,并且其中一些常量根本没有用到。

 

 

 

Abs

 

abs.mcfunction

 

  1. # Absolute x=-x(x<0) || x=x(x>=0)
  2. scoreboard players operation @s abs_out_0 = @s abs_arg_0
  3. execute if entity @s[scores={abs_out_0=..-1}] run scoreboard players operation @s abs_out_0 *= minus_one constants

复制代码

当a>=0时,|a|=a,反之|a|=-a

 

Pow

 

pow.mcfunction

 

  1. # Pow
  2. scoreboard players operation @s pow_tmp_0 = @s pow_arg_1
  3. scoreboard players operation @s pow_out_0 = @s pow_arg_0
  4. scoreboard players remove @s pow_tmp_0 1
  5. execute if score @s pow_tmp_0 >= one constants if score @s pow_arg_1 > one constants run function math:pow/iteration
  6. execute if score @s pow_arg_1 = zero constants run scoreboard players set @s pow_out_0 1
  7. execute if score @s pow_arg_1 < zero constants run scoreboard players set @s pow_out_0 0

复制代码

pow/iteration.mcfunction

 

  1. scoreboard players operation @s pow_out_0 *= @s pow_arg_0
  2. scoreboard players remove @s pow_tmp_0 1
  3. execute if score @s pow_tmp_0 >= one constants run function math:pow/iteration

复制代码

我们在主函数中做第一次处理,随后判断条件进入迭代。在迭代中我们每次都将结果*底数,并且将临时量-1。随后判断条件继续迭代。最后我们回到主函数,对指数为0或指数<0的情况做特殊处理。

 

Sqrt

 

sqrt.mcfunction

 

  1. # SquareRoot
  2. # Newton Iteration f(x1)=(f(x0)+r/f(x0))/2
  3. # For precision, r=r*10^4, so we get result*100
  4. scoreboard players operation @s abs_arg_0 = @s sqrt_arg_0
  5. function math:abs/abs
  6. scoreboard players operation @s sqrt_out_0 = @s abs_out_0
  7. scoreboard players operation @s sqrt_out_0 *= precision constants
  8. scoreboard players operation @s sqrt_tmp_0 = @s sqrt_out_0
  9. scoreboard players operation @s sqrt_out_0 /= two constants
  10. scoreboard players operation @s sqrt_tmp_0 -= @s sqrt_out_0
  11. execute if score @s sqrt_tmp_0 > sqrt_diff constants run function math:sqrt/iteration
  12. scoreboard players set @s sqrt_tmp_0 0
  13. scoreboard players set @s sqrt_tmp_1 0

复制代码

sqrt/iteration.mcfunction

 

  1. scoreboard players operation @s sqrt_tmp_1 = @s sqrt_arg_0
  2. scoreboard players operation @s sqrt_tmp_1 *= precision constants
  3. scoreboard players operation @s sqrt_tmp_1 /= @s sqrt_out_0
  4. scoreboard players operation @s sqrt_tmp_1 += @s sqrt_out_0
  5. scoreboard players operation @s sqrt_tmp_1 /= two constants
  6. scoreboard players operation @s sqrt_tmp_0 = @s sqrt_out_0
  7. scoreboard players operation @s sqrt_out_0 = @s sqrt_tmp_1
  8. scoreboard players operation @s sqrt_tmp_0 -= @s sqrt_out_0
  9. execute if score @s sqrt_tmp_0 > sqrt_diff constants run function math:sqrt/iteration

复制代码

我们对平方根的处理使用了牛顿迭代法(Newton Iteration)。即f(xn+1)=(f(xn)+a/f(xn))/2迭代,直到f(xn-1)-f(xn+1)<规定的精度为止。至于具体推导等,请自行百度。

 

我们在主函数中对 输入数/2 随后检测误差,如果不满足条件,进入迭代。在迭代中我们对上次的输出进行运算,计算误差,判断条件并进入迭代直至满足条件为止。由于我们将输入*10^4,所以输出是 原本输出*10^2。故常量sqrt_diff实际为 规定值/10^2。

 

Vector/Length

 

length.mcfunction

 

  1. scoreboard players set @s sqrt_arg_0 0
  2. scoreboard players operation @s leng_out_0 = @s leng_arg_0
  3. scoreboard players operation @s leng_out_0 *= @s leng_out_0
  4. scoreboard players operation @s sqrt_arg_0 += @s leng_out_0
  5. scoreboard players operation @s leng_out_0 = @s leng_arg_1
  6. scoreboard players operation @s leng_out_0 *= @s leng_out_0
  7. scoreboard players operation @s sqrt_arg_0 += @s leng_out_0
  8. scoreboard players operation @s leng_out_0 = @s leng_arg_2
  9. scoreboard players operation @s leng_out_0 *= @s leng_out_0
  10. scoreboard players operation @s sqrt_arg_0 += @s leng_out_0
  11. function math:sqrt/sqrt
  12. scoreboard players operation @s leng_out_0 = @s sqrt_out_0

复制代码

向量长度计算公式为 √x2+y2+z2,并且由于sqrt的结果是*10^2的,所以我们的length算出来自然也是*10^2的

 

Vector/Normalize

 

normalize.mcfunction

 

  1. scoreboard players operation @s leng_arg_0 = @s norm_arg_0
  2. scoreboard players operation @s leng_arg_1 = @s norm_arg_1
  3. scoreboard players operation @s leng_arg_2 = @s norm_arg_2
  4. scoreboard players operation @s norm_out_0 = @s norm_arg_0
  5. scoreboard players operation @s norm_out_1 = @s norm_arg_1
  6. scoreboard players operation @s norm_out_2 = @s norm_arg_2
  7. function math:vector/length/length
  8. scoreboard players operation @s pow_arg_0 = sqrt_out_prec constants
  9. scoreboard players set @s pow_arg_1 2
  10. function math:pow/pow
  11. scoreboard players operation @s norm_out_0 *= @s pow_out_0
  12. scoreboard players operation @s norm_out_1 *= @s pow_out_0
  13. scoreboard players operation @s norm_out_2 *= @s pow_out_0
  14. scoreboard players operation @s norm_out_0 /= @s leng_out_0
  15. scoreboard players operation @s norm_out_1 /= @s leng_out_0
  16. scoreboard players operation @s norm_out_2 /= @s leng_out_0

复制代码

规格化向量的公式为 normalize(u)=(ux/||u||,uy/||u||,uz/||u||)

 

※ ||u||=length(u)

 

所以我们只需要 分量/向量的长度就可以了。但是由于length结果是*10^2的,所以我们需要将分量*(10^2)^2才能得到正确的精度……

发表评论

您必须 登录 才能发表留言!