[算法擂台]将float型变量转换为字符串,限C\C++

fireseed 2009-02-16 07:49:13
加精
[算法擂台]将float型变量转换为字符串
打开CSDN倒处都是“某公司面试题”,今天我也来出一道,如果我是面试官,我会用这道题的。

目标:写一个函数,实现将float型变量转换为字符串的功能。

概念
科学计数法的形式为a*(n^m),前面的小数部分称为尾数,后面n^m中n称为底数,m称为阶数或指数
系统库指的是通常情况下编程环境默认提供的C标准库和STL

格式
函数头定义如下。

int ftostr( char *pBuf, int nSize, float fNum )

pBuf用来存放转换后的字符串,nSize为用户指定的pBuf的大小(以字节为单位),fNum是待转换的浮点数。
返回值为转换后的字符串长度。空间不足或出错时返回0。

要求
* 用C或C++语言实现,可以使用系统库,但不得使用任何其它辅助函数或类。
* 不得使用系统库中已提供的相关转换函数或类。
* 以十进制的科学计数法表示,形式为:-3.354e-44,表示-3.354*(10^-44)。尾数的区间为(10,-10);
* 当pBuf的空间不足时,可适当截短尾数的精度。当pBuf的空间不够存放符号或阶数时,返回0;

提示
C\C++语言中的浮点数是以IEEE745标准的格式存放的。float为32位,倒字节序存储。最高位为符号,1表示负。30-23位为阶数,转为十进制后减127可得到原阶数,以m表示。22-1位为尾数,以An表示第n位尾数:A22 * (1/2) + A21 * (1/4) + …… + A1 * (1/(2^22))可得到十进制的纯小数。纯小数加1成为1.xxxx的形式,然后乘以(2^m)即得到原浮点数。

评判标准
* 有思路简介,代码有注释
* 算法准确,稳定,无异常
* 效率较高

附:
一个分析浮点型变量二进制数据的例程:

float fTest = 54345.3435f;
unsigned char *pData = (unsigned char*)&fTest;
float fRes = 1.0f; // 表示1.xxx
// 提取尾数
for ( unsigned int i = 0; i < 23; ++i )
{
// 确定尾数所在的字节,并计算当前的位在字节中的位置
unsigned char nBit = pData[ 2 - ( i + 1 ) / 8 ] << ( i + 1 ) % 8;
nBit >>= 7;
fRes += (float)nBit / ( 2 << i ); // 2<<i相当于2^i
}
// 提取阶码,阶码位于第30位到第23位
unsigned char nExp = pData[3];
nExp <<= 1; // 除掉附号位
nExp |= ( pData[2] >> 7 ); // 与下个字节的首位合并,组成阶码
nExp -= 0x7F; // 减127得到原阶数
fRes *= pow( 2.0f, (float)*(char*)&nExp );
// 提取符号位,位于最高位,第31位
if ( pData[3] & 0x80 )
{ // 最高位为1则为负,为0则为正
fRes = -fRes;
}
cout << setprecision(10) << fTest << "->" << fRes;


上面例程仅供参考,目的是为了解释浮点数编码,不保证运行结果的正确性。
具体的浮点数编码格式以IEEE745为准,见:
http://www.psc.edu/general/software/packages/ieee/ieee.php
此题的题面描述难免有错漏之处,敬请提醒斧正!
...全文
8386 141 打赏 收藏 转发到动态 举报
写回复
用AI写文章
141 条回复
切换为时间正序
请发表友善的回复…
发表回复
leolee82 2012-10-18
  • 打赏
  • 举报
回复
这个没啥难度吧 用VB写过,理解IEEE标准就没啥难度了,主要就是float二进制的指数部分转换成10进制再减个127,尾数部分加1后转换成10进制. C++中用位操作就行。
jupiterwang 2012-10-17
  • 打赏
  • 举报
回复
这个需要mark一下,可以好好看看
王旺旺旺 2011-10-22
  • 打赏
  • 举报
回复
C++ 11有 string to_string(float);
npuhuxl 2011-10-05
  • 打赏
  • 举报
回复
感觉
这个需要把IEEE745规则记下来,甚至每个部分占几位都要记住
而且程序要处理的细节太多,面试那么短的时间,那么紧张的环境中基本上不能做好,除非ACM大牛降临
题目很不错,但是作为面试题不太好。
qingcairousi 2011-06-24
  • 打赏
  • 举报
回复
[Quote=引用 129 楼 xushuai0794 的回复:]

楼主,你那个关于float在内存中的储存方式是VC++6里面的,不过在不同的编译器里面float在内存中的储存方式是不同的啊。。。。

其实我觉得这个问题你没必要这么麻烦,去做个共同体,直接可以把float的形式转换成int形式的,我以前做过,也试验过,可以的。。。然后把int的数转换成子字符串就ok了。。。
[/Quote]
不对吧?双精度浮点和单精度浮点都是有IEEE754这个标准的,一般只要没有非常蛋疼的理由,是不会去违反标准的,所以一般情况下单精度和双精度浮点的表示方法的一致性是有保证的我认为。
su_yuxuan 2011-05-26
  • 打赏
  • 举报
回复
沉吧!毫不犹豫!!!
静革 justme0.com 2011-05-17
  • 打赏
  • 举报
回复
一、int/long/float/double 转 字符串

方法1:itoa, ltoa(a表示array数组的意思)

头文件:stdlib.h

示例:

int a = 3;

long b = 23;

char buf1[30] = "";
itoa(a, buf1, 10);//10表示十进制,buf1保存的内容为"3"
char buf2[30] = "";
ltoa(b, buf2, 10);//10表示十进制,buf2保存的内容为"32"

又如:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int number = 12345;
char string[25];
itoa(number, string, 10);
printf("integer = %d string = %s\n", number, string);

return 0;
}




方法2:sprintf

头文件:stdio.h


示例:

int a = 3;
float b = 4.2f;
char buf[30] = "";
sprintf(buf, "%d,%f", a, b);//buf保存的内容为"3,4.2",可对比printf

方法3:ostringstream

头文件:#include <sstream>

using namespace std;

示例:

int a = 3;
float b = 4.2f;
ostringstream s1;
s1<<a<<","<<b;//可对比cout
string s2 = s1.str();//s2保存的内容为"3,4.2"

二、字符串 转 int/long/float/double




方法1:atoi,atol,atof

头文件:stdlib.h

示例:

int a = atoi("32");

long b = atol("333");

double c = atof("23.4");

方法2:strtol, strtod

头文件:stdlib.h

示例:

long b = strtol("333", NULL, 10);//10表示十进制

double c = strtod("32.3", NULL);




方法3:sscanf

头文件:stdio.h

示例:

int a;
float b;
sscanf("23 23.4", "%d %f", &a, &b);//对比scanf

方法4:istringstream

头文件:#include <sstream>

using namespace std;

示例:

int a;
float b;
istringstream s1("23 23.4");
s1>>a>>b;//对比cin


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wu_uuww/archive/2011/04/20/6336731.aspx
pcliuguangtao 2011-03-21
  • 打赏
  • 举报
回复
[Quote=引用 78 楼 xmrforever 的回复:]

有点复杂
用_gcvt( double value, int digits, char *buffer );比较方便
[/Quote]
恩,挺简单,并且支持负值和科学计数法
laal35568 2011-03-16
  • 打赏
  • 举报
回复
shetianlang2010 2011-02-11
  • 打赏
  • 举报
回复
邪恶之狗啊

哈哈 LZ很强大
sparklxd 2010-12-20
  • 打赏
  • 举报
回复
头好晕
flxue 2010-11-03
  • 打赏
  • 举报
回复
没记错的话,有本书里好像仔细分析过设计int 和float时候设计师们好像故意调整那个浮点的格式使得int和float可以很直接的与129楼的高人那样转换的,有时间回顾一下,都是牛人!学习中[Quote=引用 129 楼 xushuai0794 的回复:]
楼主,你那个关于float在内存中的储存方式是VC++6里面的,不过在不同的编译器里面float在内存中的储存方式是不同的啊。。。。

其实我觉得这个问题你没必要这么麻烦,去做个共同体,直接可以把float的形式转换成int形式的,我以前做过,也试验过,可以的。。。然后把int的数转换成子字符串就ok了。。。
[/Quote]
xushuai0794 2010-07-12
  • 打赏
  • 举报
回复
楼主,你那个关于float在内存中的储存方式是VC++6里面的,不过在不同的编译器里面float在内存中的储存方式是不同的啊。。。。

其实我觉得这个问题你没必要这么麻烦,去做个共同体,直接可以把float的形式转换成int形式的,我以前做过,也试验过,可以的。。。然后把int的数转换成子字符串就ok了。。。
zhuweiping2003 2010-06-02
  • 打赏
  • 举报
回复
关注一个
bolary 2010-04-25
  • 打赏
  • 举报
回复
mark
jacker_ 2010-01-14
  • 打赏
  • 举报
回复
学习学习了
z13759561330 2009-11-20
  • 打赏
  • 举报
回复
这是我项目中的一个,虽然不支持科学计数法,但可以指定小数精度和千位分隔符
//格式化数值到字符串
const std::string EVOLVE::format_value_string_A(double value,
int decimal, //小数位数,小于0自动
bool bKiloChar)//千位分隔符
{
const char* num[]={"0","1","2","3","4","5","6","7","8","9"};
std::string strRet = "";
if(value < 0)
{
strRet += "-";
value = -value;
}

if(decimal >= 0)
{
decimal = min(decimal, 10); //小数位数最多精确到小数点后10位
switch(decimal)
{
case 0:
value += 0.5;
break;
case 1:
value += 0.05;
break;
case 2:
value += 0.005;
break;
case 3:
value += 0.0005;
break;
case 4:
value += 0.00005;
break;
case 5:
value += 0.000005;
break;
case 6:
value += 0.0000005;
break;
case 7:
value += 0.00000005;
break;
case 8:
value += 0.000000005;
break;
case 9:
value += 0.0000000005;
break;
case 10:
value += 0.00000000005;
break;
}
}

double xiaoshu = value;
if(xiaoshu >= 100000000)xiaoshu -= (double)(((long)(xiaoshu/100000000))*100000000);
if(xiaoshu >= 1)xiaoshu -= (double)(long)xiaoshu;

double zhengshu = value - xiaoshu;
if(zhengshu >= 1)
{
double q_s = 1; //权数
int k = 0; //有效位数
double n = zhengshu;
while(n>=10)
{
n/=10,
q_s *=10,
k++;
}
k+=1;

n = zhengshu;
long wen = 0;
while(--k>=0)
{
strRet += num[wen = (long)(n/q_s)];
if(bKiloChar && 0!=k && 0==k%3)strRet += ",";
n -= wen*q_s;
q_s /= 10;
}
}
else strRet += "0";

if(0!=decimal && xiaoshu>=0.00000000001)
{
strRet += ".";
double q_s = 10;
long wen = 0;
double n = xiaoshu;
if(decimal < 0)
{
while(n > 0.00000000001)
{
strRet += num[wen = (long)(n*q_s+0.00000000001)];
n -= (double)wen/q_s;
q_s *= 10;
}
}
else
{
while(decimal>0 && n>0.00000000001)
{
strRet += num[wen = (long)(n*q_s+0.00000000001)];
n -= (double)wen/q_s;
q_s *= 10;
--decimal;
}
}
}
return strRet;
}
王旺旺旺 2009-11-19
  • 打赏
  • 举报
回复

//由数值转换为字符串.
//浮点数需要预先设置精度.


#include <string>
#include <sstream>

using namespace std;


template <typename T>
std::string ValueToStr(T value)
{
ostringstream ost;
ost << value;
return ost.str();
}

//=================================

#include "main.h"

#include <iostream>

using namespace std;

int main()
{
long testValue = 123456789;
string hello = ValueToStr(testValue);
cout << "value : " << testValue << endl;
cout << "string : " << hello.c_str() << endl;
}
miracle159 2009-09-26
  • 打赏
  • 举报
回复
mark
acrobatyuer 2009-09-04
  • 打赏
  • 举报
回复
有点深度。。。

留下看。。。
加载更多回复(121)

64,652

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧