整型和浮点类型的转换,int与float,double互转的快速实现(在没有对应的汇编指令情况下)

8 篇文章 0 订阅
2 篇文章 0 订阅

如果没有类型转换对应的汇编指令,我们可以用浮点加法来完成整型和浮点类型的互转。

注意:需要实现IEE浮点环境(float,double数据类型),不能用FPU的80位浮点做临时运算!

如果有对应的汇编指令,调用之明显更简单高效,然而有些情况下类型转换会溢出,这要注意,计算机不会检查溢出而返回错误结果。一般来说,一次整型和浮点类型的互转的消耗和浮点加法一样,实际就是用浮点加法实现的类型转换。代码如下(不解释):

typeconvert.h

#include <stdint.h>

//以下所有实现经过了严格测试,可以保证无误。其中,标准实现不会溢出,而用指令转换可能溢出。

/**
 * 转换後,得到32位有符号整型(未考虑转换溢出)。
**/
int32_t convert_to_int32(double a)
{
	a+=6755399441055744.0;
	return *(int32_t*)&a;
}

/**
 * 转换後,得到23位有效数字之有符号整型(未考虑转换溢出)。即,a in[-0x400000,0x400000.8]
**/
int32_t convert_to_int23(float a)
{
	a+=12582912.0f;
	return *(int32_t*)&a-0x4B400000;
}

/**
 * 转换後,得到24位有效数字之有符号整型(未考虑转换溢出)。即,a in[-0x7FFFFF,0x7FFFFF]
**/
int32_t convert_to_int24(float a)
{
	if(a<0)
	{
		a-=8388608.0f;
		return -((*(int32_t*)&a)&0x7FFFFF);
	}
	else
	{
		a+=8388608.0f;
		return (*(int32_t*)&a)&0x7FFFFF;
	}
}

/**
 * 标准实现,考虑了转换溢出的问题
**/
int32_t convert_to_int32(float a)
{
	float convert23_to_float(int32_t i);
	if(a>=-(float)(1<<31))return (1<<31)-1;
	if(a<(float)(1<<31))return (1<<31);
	int32_t n=(*(int32_t*)&a)>>31;
	int32_t i;
	(*(int32_t*)&a)&=0x7FFFFFFF;
	if(a>8388607.0f)
	{
		(*(int32_t*)&a)-=0x7800000;
		float b=a+8388608.0f;
		i=(*(int32_t*)&b)&0x7FFFFF;
		a-=convert23_to_float(i);
		a+=384.0f;
		i=(i<<15)+*(int16_t*)&a;
	}
	else
	{
		a+=8388608.0f;
		i=(*(int32_t*)&a)&0x7FFFFF;
	}
	return (i^n)-n;
}

/**
 * 转换後,得到52位有效数字之有符号整型(未考虑转换溢出)。即,a in[-0x8000000000000LL,0x8000000000000.8LL]
**/
int64_t convert_to_int52(double a)
{
	a+=6755399441055744.0;
	return *(int64_t*)&a-0x4338000000000000LL;
}

/**
 * 转换後,得到53位有效数字之有符号整型(未考虑转换溢出)。即,a in[-0xFFFFFFFFFFFFFLL,0xFFFFFFFFFFFFFLL]
**/
int64_t convert_to_int53(double a)
{
	if(a<0)
	{
		a-=4503599627370496.0;
		return -((*(int64_t*)&a)&0xFFFFFFFFFFFFFLL);
	}
	else
	{
		a+=4503599627370496.0;
		return (*(int64_t*)&a)&0xFFFFFFFFFFFFFLL;
	}
}

/**
 * 标准实现,考虑了转换溢出的问题
**/
int64_t convert_to_int64(double a)
{
	double convert52_to_double(int64_t i);
	if(a>=-(double)(1LL<<63))return (1LL<<63)-1;
	if(a<(double)(1LL<<63))return (1LL<<63);
	int64_t n=(*(int64_t*)&a)>>63;
	int64_t i;
	(*(int64_t*)&a)&=0x7FFFFFFFFFFFFFFFLL;
	if(a>4503599627370495.0)
	{
		(*(int64_t*)&a)-=0x1F0000000000000LL;
		double b=a+4503599627370496.0;
		i=(*(int64_t*)&b)&0xFFFFFFFFFFFFFLL;
		a-=convert52_to_double(i);
		a+=3145728.0;
		i=(i<<31)+*(int32_t*)&a;
	}
	else
	{
		a+=4503599627370496.0;
		i=(*(int64_t*)&a)&0xFFFFFFFFFFFFFLL;
	}
	return (i^n)-n;
}

/**
 * 标准实现,考虑了转换溢出的问题
**/
int64_t convert_to_int64(float a)
{
	return convert_to_int64((double)a);
}

/**
 * i是23位有效数字之有符号整型。即,i in[-0x400000,0x400000]
**/
float convert23_to_float(int32_t i)
{
	i+=0x4B400000;
	return (*(float*)&i)-12582912.0f;
}

/**
 * i是24位有效数字之有符号整型。即,i in[-0x7FFFFF,0x7FFFFF]
**/
float convert24_to_float(int32_t i)
{
	if(i<0)
	{
		i=0xCB000000-i;
		return (*(float*)&i)+8388608.0f;
	}
	else
	{
		i+=0x4B000000;
		return (*(float*)&i)-8388608.0f;
	}
}

/**
 * 标准实现
**/
float convert_to_float(int32_t i)
{
	int32_t n=i>>31;
	float a;
	i=(i^n)-n;
	if((uint32_t)i>8388607)
	{
		int32_t j=(uint32_t)i>>23;
		i&=0x7FFFFF;
		i+=0x4B000000;
		a=(*(float*)&i)-8388608.0f;
		j+=0x56800000;
		a+=(*(float*)&j)-(float)(1LL<<46);
	}
	else
	{
		i+=0x4B000000;
		a=(*(float*)&i)-8388608.0f;
	}
	(*(int32_t*)&a)|=(n&0x80000000);
	return a;
}

/**
 * 标准实现
**/
float convert_to_float(int64_t i)
{
	double convert_to_double(int64_t i);
	return (float)convert_to_double(i);
}

/**
 * i是53位有效数字之有符号整型。即,i in[-0xFFFFFFFFFFFFFLL,0xFFFFFFFFFFFFFLL]
**/
double convert53_to_double(int64_t i)
{
	if(i<0)
	{
		i=0xC330000000000000LL-i;
		return (*(double*)&i)+4503599627370496.0f;
	}
	else
	{
		i+=0x4330000000000000LL;
		return (*(double*)&i)-4503599627370496.0f;
	}
}

/**
 * i是52位有效数字之有符号整型。即,i in[-0x8000000000000LL,0x7FFFFFFFFFFFFLL]
**/
double convert52_to_double(int64_t i)
{
	i+=0x4338000000000000LL;
	return (*(double*)&i)-6755399441055744.0;
}

/**
 * 标准实现
**/
double convert_to_double(int32_t i)
{
	return convert52_to_double((int64_t)i);
}

/**
 * 标准实现
**/
double convert_to_double(int64_t i)
{
	int64_t n=i>>63;
	double a;
	i=(i^n)-n;
	if((uint64_t)i>4503599627370495LL)
	{
		int64_t j=(uint64_t)i>>32;
		i&=0xFFFFFFFF;
		a=convert52_to_double(i);
		j+=0x4530000000000000LL;
		a+=(*(double*)&j)-(double)(1LL<<52)*(double)(1LL<<32);
	}
	else
	{
		i+=0x4330000000000000LL;
		a=(*(double*)&i)-4503599627370496.0;
	}
	(*(int64_t*)&a)|=(n&0x8000000000000000LL);
	return a;
}

测试代码:ConsoleApplication1.cpp

// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "typeconvert.h"
#include <stdio.h>
#include <xmmintrin.h>
#include <emmintrin.h>
#define PR(x,a) printf("error in "#x" %lf\n",(double)a)

void d2int32()
{
	double a = (1 << 31)-0.5,b= -(1 << 31) + 0.5;
	int i = (1 << 31);
	while (a < b)
	{
		if (i != convert_to_int32(a))PR(d2int32, a);
		a += 1.0;
		if (i != convert_to_int32(a))PR(d2int32, a);
		a += 1.0;
		i+=2;
	}
}

void f2int23()
{
	double a = -(1 << 22) - 0.5, b = (1 << 22) + 0.5;
	int i = -(1 << 22);
	while (a < b)
	{
		if (i != convert_to_int23((float)a))PR(f2int23, a);
		a += 1.0;
		if (i != convert_to_int23((float)a))PR(f2int23, a);
		a += 1.0;
		i += 2;
	}
	printf("%d\n", convert_to_int23((float)b));
}

void f2int24()
{
	double a = -(1 << 23) - 0.5, b = (1 << 23) + 0.5;
	int i = -(1 << 23);
	while (a < b)
	{
		if (i != convert_to_int24((float)a))PR(f2int24, a);
		a += 1.0;
		if (i != convert_to_int24((float)a))PR(f2int24, a);
		a += 1.0;
		i += 2;
	}
}

void f2int32()
{
	double a = (1 << 31) - 0.5, b = -(double)(1 << 31) + 0.5;
	bool display = true;
	while (a <= b)
	{
		float c = a;
		if (_mm_cvtss_si32(_mm_load_ss(&c)) != convert_to_int32(c) && display) {
			PR(f2int32, a);
			display = false;
		}
		a += 1.0;
	}
	float c = 2147483584.5;
	printf("%d\n", _mm_cvtss_si32(_mm_load_ss(&c)));//这个方法会溢出
}

void d2int52()
{
	double a = -(1LL << 51) - 0.5, b = -(1LL << 51) + (1LL << 16) + 0.5;
	while (a <= b)
	{
		if (_mm_cvtsd_si64(_mm_load_sd(&a)) != convert_to_int52(a))PR(d2int52, a);
		a += 1.0;
	}
	a = -(1LL << 16) - 0.5, b = (1LL << 16) + 0.5;
	while (a <= b)
	{
		if (_mm_cvtsd_si64(_mm_load_sd(&a)) != convert_to_int52(a))PR(d2int52, a);
		a += 1.0;
	}
	a = (1LL << 51) - (1LL << 16) - 0.5, b = (1LL << 51) + 0.5;
	while (a <= b)
	{
		if (_mm_cvtsd_si64(_mm_load_sd(&a)) != convert_to_int52(a))PR(d2int52, a);
		a += 1.0;
	}
	printf("%lld\n", convert_to_int52(b));
}

void d2int53()
{
	double a = -(1LL << 52) + 0.5, b = -(1LL << 52) + (1LL << 16) + 0.5;
	while (a <= b)
	{
		if (_mm_cvtsd_si64(_mm_load_sd(&a)) != convert_to_int53(a))PR(d2int53, a);
		a += 1.0;
	}
	a = -(1LL << 16) - 0.5, b = (1LL << 16) + 0.5;
	while (a <= b)
	{
		if (_mm_cvtsd_si64(_mm_load_sd(&a)) != convert_to_int53(a))PR(d2int53, a);
		a += 1.0;
	}
	a = (1LL << 52) - (1LL << 16) - 0.5, b = (1LL << 52);
	while (a <= b)
	{
		if (_mm_cvtsd_si64(_mm_load_sd(&a)) != convert_to_int53(a))PR(d2int53, a);
		a += 1.0;
	}
}

void d2int64()
{
	double a = (double)(1LL << 63) + (1LL<<10), b = (double)(1LL << 63) + (1LL << 27) + (1LL << 10);
	while (a <= b)
	{
		if (_mm_cvtsd_si64(_mm_load_sd(&a)) != convert_to_int64(a))PR(d2int64, a);
		a += (1LL << 11);
	}
	a = -(1LL << 16) - 0.5, b = (1LL << 16) + 0.5;
	while (a <= b)
	{
		if (_mm_cvtsd_si64(_mm_load_sd(&a)) != convert_to_int64(a))PR(d2int64, a);
		a += 1.0;
	}
	a = -(double)(1LL << 63) - (1LL << 27) + (1LL << 10), b = -(double)(1LL << 63) + (1LL << 10);
	while (a <= b)
	{
		if (_mm_cvtsd_si64(_mm_load_sd(&a)) != convert_to_int64(a))PR(d2int64, a);
		a += (1LL << 11);
	}
	printf("%lld\n", _mm_cvtsd_si64(_mm_load_sd(&b)));//这个方法会溢出
}

void f2int64()
{
	printf("f2int64 true!\n");
}

void i23float()
{
	for (int i = -0x400000; i <= 0x400000; i++)
	{
		if (convert23_to_float(i) != (float)i)
		{
			PR(i23float, i);
		}
	}
}

void i24float()
{
	for (int i = -0x7FFFFF; i <= 0x7FFFFF; i++)
	{
		if (convert24_to_float(i) != (float)i)
		{
			PR(i24float, i);
		}
	}
}

void i32float()
{
	for (int i = 0x80000000; i != 0x7FFFFFFF; i++)
	{
		if (convert_to_float(i) != (float)i)
		{
			PR(i32float, i);
		}
		if (i == 0x80001000)i = 0x7FFFF000;
	}
}

void i64float()
{
	printf("i64float true!\n");
}

void i53double()
{
	for (int64_t i = -0xFFFFFFFFFFFFFLL; i != 0xFFFFFFFFFFFFFLL; i++)
	{
		if (convert53_to_double(i) != (double)i)
		{
			PR(i53double, i);
		}
		if (i == -0xFFFFFFFFFF000LL)i = -0xFFF;
		if (i == 0xFFF)i = 0xFFFFFFFFFF000LL;
	}
}

void i52double()
{
	for (int64_t i = -0x8000000000000LL; i != 0x7FFFFFFFFFFFFLL; i++)
	{
		if (convert52_to_double(i) != (double)i)
		{
			PR(i52double, i);
		}
		if (i == -0x7FFFFFFFFF000LL)i = -0xFFF;
		if (i == 0xFFF)i = 0x7FFFFFFFFF000LL;
	}
}

void i32double()
{
	printf("i32double true!\n");
}

void i64double()
{
	for (int64_t i = -0x8000000000000000LL; i != 0x7FFFFFFFFFFFFFFFLL; i++)
	{
		if (convert_to_double(i) != (double)i)
		{
			PR(i64double, i);
		}
		if (i == -0x7FFFFFFFFF000000LL)i = -0xFFFFFF;
		if (i == 0xFFFFFF)i = 0x7FFFFFFFFF000000LL;
	}
}

int main()
{
	printf("start\n");
	d2int32();
	printf("\n");
	f2int23();
	printf("\n");
	f2int24();
	printf("\n");
	f2int32();
	printf("\n");
	d2int52();
	printf("\n");
	d2int53();
	printf("\n");
	d2int64();
	printf("\n");
	f2int64();
	printf("\n");
	i23float();
	printf("\n");
	i24float();
	printf("\n");
	i32float();
	printf("\n");
	i64float();
	printf("\n");
	i53double();
	printf("\n");
	i52double();
	printf("\n");
	i32double();
	printf("\n");
	i64double();
	printf("end\n");
	return 0;
}

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值