R语言min.mpfr调用返回意外精度的底层原因咨询
问题复现代码
foob <- as.bigz(5:7) min(foob) # Big Integer ('bigz') : # [1] 5 .bigz2mpfr(prev) # 1 'mpfr' number of precision 4 bits # [1] 5 min(.bigz2mpfr(foob)) # 1 'mpfr' number of precision 53 bits # [1] 5 min(mpfr(5:7,5)) # 1 'mpfr' number of precision 53 bits # [1] 5
精度跳变的底层运行逻辑
53位是R内置双精度浮点数(double)的默认尾数精度,该精度跳变是Rmpfr包中min方法的分支设计+转换逻辑缺陷共同导致的,具体执行流程如下:
- 对mpfr对象调用
min()方法时,函数首先会做精度阈值判断:如果输入mpfr向量所有元素的精度都不超过53位,会优先走快速比较分支。这个分支的设计初衷是利用基础R的double类型运算速度快的特性,先把所有mpfr元素转成基础double类型完成比较,快速定位最小值对应的元素位置,规避高精度运算的额外性能开销。 - 该分支存在一个长期未修复的逻辑缺陷:定位到最小值位置后,函数回写结果时没有直接提取原始mpfr向量中对应位置的元素,因此无法继承原始对象的低精度属性;相反,它会把比较过程中生成的double类型最小值重新传入
as.mpfr()做转换,而as.mpfr()接收double类型输入时,会默认给返回值分配双精度对应的53位精度,最终就出现了精度被抬升到53位的现象。 - 当初始创建的mpfr对象精度高于53位(例如示例中
prec = 60的对象)时,函数会自动跳过这个快速比较分支:因为精度超过53位的数值转double必然出现精度丢失,无法保证比较结果的正确性。此时函数会直接调用gmp包的bigz/bigq比较逻辑在高精度层面完成运算,全程不涉及double类型转换,返回结果会保留原始精度,不会出现精度跳变。
测试代码中.bigz2mpfr(prev)返回4位精度的结果也符合上述逻辑:直接对单个bigz类型结果调用.bigz2mpfr()时,不会触发min.mpfr的快速比较分支,转换函数会根据整数值的实际二进制长度计算所需最小精度——整数5的二进制表示为101,算上符号位共需要4位精度,和返回结果完全匹配。
内容的提问来源于stack exchange,提问作者Carl Witthoft
相关产品推荐
相关产品推荐

