C语言中重要函数的简要分析及实例
1. strspn与strcspn
2. strtok与strpbrk
3. strstr, strchr与strrchr
4. 字符串与数值之间的转换:atoi,atol,atof,strtod,strtol,strtoul
5. frexp和ldexp
1. strspn与strcspn
(1)函数strspn:
size_t strspn ( const char * str1, const char * str2 );
功 能: 在串中查找指定字符集的子集的第一次出现,如果str1中的所有字符都在str2中出现过,那么返回str1的长度。如果第一个字符就不在str2中,那么返回0.
对于下面的程序:
(2)函数strcspn:
size_t strcspn ( const char * str1, const char * str2 );
功 能: 在串中查找第一个给定字符集内容的段的开始位置。
对于下面的程序:
2. strtok与strpbrk
(1) 函数strtok
char * strtok ( char * str, const char * delimiters );
功 能: 查找由在第二个串中指定的分界符分隔开的单词, 即源串中除去了含有分隔串中的所有字符后余下的一段段的字符串,每调用一次找到一串,找不到则返回空串。
strtok使用注意事项:
* These functions modify their first argument.
* These functions cannot be used on constant strings.
* The identity of the delimiting character is lost.
* The strtok() function uses a static buffer while parsing, so it's not thread safe.
下面是一段程序:
输出如下:
上图中第一行是利用strtok进行分隔得到的多个字符串。
第2行是原始的字符串str,第3行是用strtok处理后原始字符串str2。
这儿可以得到如下几个知识点:
strtok是对原始的字符串进行修改的,是将其中的分隔字符替换为'\0',这样每次调用strtok之后返回值指向当前找到的新字符串的头,而且从这个头开始,所遇到的第一个分隔符已经替换为'\0',所以打印token可以得到分隔后的字符串,并且由于这个函数使用了静态变量所以可以利用循环不断的进行操作。
这样,既然我们明白了strtok是要对原始的字符串进行修改,就应该注意到了,其参数不能是类似:
char *str= "A stringtof , ,tokensnand some more tokens";
这样的常量字符串,因为这种是静态存储的,是不允许修改的,而只能是字符数组形式的:
char str2[]= "A stringtof , ,tokensnand some more tokens";
(2) 函数strpbrk
char * strpbrk ( const char *str1, const char *str2 );
功能:在串中查找给定字符集中的字符所在的位置。
看下面的程序:
输出如下:
从上面的输出我们可以看到strpbrk主要是在字符串str中找到cset字符集中第一个出现的字符所在的位置,然后将这个指针返回。它并不修改原始的字符串,其实从它的函数声明中就可以看出来,两个参数都是const的(参数可以是常量字符串),当然不允许对字符串进行修改了。
strpbrk的一个比较好的用处就是在字符串中查找导致出现了哪些cset字符集中的字符。
一个示例程序如下:
输出如下:
为了更加适用,改成函数调用的形式如下:
输出是和上面的一样的。
下面是strpbrk的另一个用处,实现和strtok相同的功能。
既然可以找到给定的字符集,那么肯定也可以用于分隔字符串了。下面的程序就实现了这个功能。
输出如下:
需要注意的是:这个程序中和strtok一样,也对原始字符串进行了修改,将找到的一个分隔符修改为'\0'来标识字符串的结束。不然就无法知道所分隔得到的字符串是什么了。
不过也可以不对原字符串进行修改,但是这就要复制在找到一个单词的时候对这个单词进行复制到已经分配好的空间去了,这样其实效率就比较低了,所以在上面的程序中选择了修改原始的字符串。
3. strstr, strchr与strrchr
(1) 函数strstr
char * strstr ( const char *str1, const char * str2 );
功能:在str1中寻找字符串str2的第一次出现。不修改原始的字符串。
下面的一个小程序利用strstr找到了所有的出现的子字符串:
(2) 函数strchr和strrchr
char * strchr ( const char *str, int character );
char * strrchr ( const char *str, int character );
这两个函数都是用来在字符串中查找字符。
strchr是查找字符串中首次出现字符的位置,而上strrchr是查找最后一次出现
strchr的示例程序如下:
strrchr的示例程序如下:
4. 字符串与数值之间的转换
C语言主要提供了如下几个转换函数:
atof(); 将字符串转换成浮点型数
atoi(); 将字符串转换成整型数
atol(); 将字符串转换成长整型数
strtod(); 将字符串转换成浮点数
strtol(); 将字符串转换成长整型数
strtoul(); 将字符串转换成无符号长整型数
(1) strtod函数
double strtod ( const char * str, char ** endptr );
对于strtod来说合法的输入:
#An optional plus or minus sign
#A sequence of digits, optionally containing a decimal-point character
#An optional exponent part, which itself consists on an 'e' or 'E' character followed by an optional sign and a sequence of digits.
endptr保存是下一个解析得到的数值之后的下一个字符指针
一个简单的示例程序如下:
(2) 函数strtol
long int strtol ( const char * str, char ** endptr, int base );
对于strtol来说合法输入:
#An optional plus or minus sign
#An optional prefix indicating octal or hexadecimal base ("0" or "0x" respectively)
#A sequence of decimal digits (if no base prefix was specified) or either octal or hexadecimal digits if a specific prefix is present
一个示例小程序如下:
(3) 函数strtoul
unsigned long int strtoul ( const char * str, char ** endptr, int base );
合法输入如下:
#An optional prefix indicating octal or hexadecimal base ("0" or "0x" respectively)
#A sequence of decimal digits (if no base prefix was specified) or either octal or hexadecimal digits if a specific prefix is present
示例小程序如下:
(4)函数atoi
int atoi ( const char * str );
示例程序如下:
(5)函数atol
long int atol ( const char * str );
示例程序如下:
(6)函数atof
double atof ( const char * str );
示例程序如下:
5. frexp和ldexp
(1)函数frexp
double frexp (double x, int * exp );
功能:标准化浮点数, f=x*2^p, 已知f求x, p (x介于[0.5, 1] )
返回值为尾数,*exp是指数
示例程序如下:
输出:
0.500000 * 2^4 = 8.000000
(2)函数ldexp
double ldexp(double x, int exp );
功能:与frexp相反, 已知x, p求f
示例如下:
输出:
0.950000 * 2^4 = 15.200000
1. strspn与strcspn
2. strtok与strpbrk
3. strstr, strchr与strrchr
4. 字符串与数值之间的转换:atoi,atol,atof,strtod,strtol,strtoul
5. frexp和ldexp
1. strspn与strcspn
(1)函数strspn:
size_t strspn ( const char * str1, const char * str2 );
功 能: 在串中查找指定字符集的子集的第一次出现,如果str1中的所有字符都在str2中出现过,那么返回str1的长度。如果第一个字符就不在str2中,那么返回0.
对于下面的程序:
#include <stdio.h>
#include <string.h>
int main(){
int i;
const char *cset="1234567890";
char *str="129thfangzhen33332423";
i=strspn(str,cset);//i=3
i=strspn(str+5,cset);//i=0
printf("%d\n",i);
return 0;
}
#include <string.h>
int main(){
int i;
const char *cset="1234567890";
char *str="129thfangzhen33332423";
i=strspn(str,cset);//i=3
i=strspn(str+5,cset);//i=0
printf("%d\n",i);
return 0;
}
(2)函数strcspn:
size_t strcspn ( const char * str1, const char * str2 );
功 能: 在串中查找第一个给定字符集内容的段的开始位置。
对于下面的程序:
#include <stdio.h>
#include <string.h>
int main(){
int i;
const char *cset="1234567890";
char *str="129thfangzhen33332423";
i=strcspn(str,cset);
printf("%d\n",i); //i=0
i=strcspn(str+5,cset);//i=8
printf("%d\n",i);
return 0;
}
#include <string.h>
int main(){
int i;
const char *cset="1234567890";
char *str="129thfangzhen33332423";
i=strcspn(str,cset);
printf("%d\n",i); //i=0
i=strcspn(str+5,cset);//i=8
printf("%d\n",i);
return 0;
}
2. strtok与strpbrk
(1) 函数strtok
char * strtok ( char * str, const char * delimiters );
功 能: 查找由在第二个串中指定的分界符分隔开的单词, 即源串中除去了含有分隔串中的所有字符后余下的一段段的字符串,每调用一次找到一串,找不到则返回空串。
strtok使用注意事项:
* These functions modify their first argument.
* These functions cannot be used on constant strings.
* The identity of the delimiting character is lost.
* The strtok() function uses a static buffer while parsing, so it's not thread safe.
下面是一段程序:
#include <stdio.h>
#include <string.h>
int main(){
char *str= "A stringtof ,,tokensnand some more tokens";
char str2[100];
char *seps = " ,\t\n";
char *token;
int len,i;
strcpy(str2,str);
len=strlen(str);
token = strtok(str2,seps);
while( token != NULL )
{
printf("%s ", token);
token = strtok(NULL, seps);
}
printf("\n");
printf("%s\n",str);
for(i=0;i<len;i++)
if(str2[i]=='\0')//用特殊颜色打印出'\0'字符
printf("\033[0;30;41m.\033[0m");
else
printf("%c",str2[i]);
printf("\n");
}
#include <string.h>
int main(){
char *str= "A stringtof ,,tokensnand some more tokens";
char str2[100];
char *seps = " ,\t\n";
char *token;
int len,i;
strcpy(str2,str);
len=strlen(str);
token = strtok(str2,seps);
while( token != NULL )
{
printf("%s ", token);
token = strtok(NULL, seps);
}
printf("\n");
printf("%s\n",str);
for(i=0;i<len;i++)
if(str2[i]=='\0')//用特殊颜色打印出'\0'字符
printf("\033[0;30;41m.\033[0m");
else
printf("%c",str2[i]);
printf("\n");
}
输出如下:
上图中第一行是利用strtok进行分隔得到的多个字符串。
第2行是原始的字符串str,第3行是用strtok处理后原始字符串str2。
这儿可以得到如下几个知识点:
strtok是对原始的字符串进行修改的,是将其中的分隔字符替换为'\0',这样每次调用strtok之后返回值指向当前找到的新字符串的头,而且从这个头开始,所遇到的第一个分隔符已经替换为'\0',所以打印token可以得到分隔后的字符串,并且由于这个函数使用了静态变量所以可以利用循环不断的进行操作。
这样,既然我们明白了strtok是要对原始的字符串进行修改,就应该注意到了,其参数不能是类似:
char *str= "A stringtof , ,tokensnand some more tokens";
这样的常量字符串,因为这种是静态存储的,是不允许修改的,而只能是字符数组形式的:
char str2[]= "A stringtof , ,tokensnand some more tokens";
(2) 函数strpbrk
char * strpbrk ( const char *str1, const char *str2 );
功能:在串中查找给定字符集中的字符所在的位置。
看下面的程序:
int main(){
char *str = "The 3 men and 2 boys ate 5 pigsn";
char *cset="0123456789";
char *result;
int len,i;
result=str;
while((result=strpbrk(result,cset))!=NULL){
printf(">%s\n",result);
result++;
}
printf("%s\n",str);
}
char *str = "The 3 men and 2 boys ate 5 pigsn";
char *cset="0123456789";
char *result;
int len,i;
result=str;
while((result=strpbrk(result,cset))!=NULL){
printf(">%s\n",result);
result++;
}
printf("%s\n",str);
}
输出如下:
从上面的输出我们可以看到strpbrk主要是在字符串str中找到cset字符集中第一个出现的字符所在的位置,然后将这个指针返回。它并不修改原始的字符串,其实从它的函数声明中就可以看出来,两个参数都是const的(参数可以是常量字符串),当然不允许对字符串进行修改了。
strpbrk的一个比较好的用处就是在字符串中查找导致出现了哪些cset字符集中的字符。
一个示例程序如下:
int main(){
char *str = "This is a sample string";
char *key = "aeiou";
char * pch,*pch2;
int pos;
printf ("Vowels in '%s':\n",str);
pch=str;
while ((pch = strpbrk (pch, key))!= NULL) {
pos=pch-str;
printf ("%c %d\n" , *pch,pos);
pch++;
}
return 0;
}
char *str = "This is a sample string";
char *key = "aeiou";
char * pch,*pch2;
int pos;
printf ("Vowels in '%s':\n",str);
pch=str;
while ((pch = strpbrk (pch, key))!= NULL) {
pos=pch-str;
printf ("%c %d\n" , *pch,pos);
pch++;
}
return 0;
}
输出如下:
为了更加适用,改成函数调用的形式如下:
int getchars(int *chars,const char *line,const char *key){
int count=0;
const char*pch;
pch=line;
while((pch=strpbrk(pch,key))!=NULL){
chars[count++]=pch-line;
pch++;
}
return count;
}
int main(){
char *str = "This is a sample string";
char *key = "aeiou";
int chars[20];
int count;
int i;
printf ("Vowels in '%s':\n",str);
count=getchars(chars,str,key);
for(i=0;i<count;i++){
printf("%d: %c\n",chars[i],str[chars[i]]);
}
return 0;
}
int count=0;
const char*pch;
pch=line;
while((pch=strpbrk(pch,key))!=NULL){
chars[count++]=pch-line;
pch++;
}
return count;
}
int main(){
char *str = "This is a sample string";
char *key = "aeiou";
int chars[20];
int count;
int i;
printf ("Vowels in '%s':\n",str);
count=getchars(chars,str,key);
for(i=0;i<count;i++){
printf("%d: %c\n",chars[i],str[chars[i]]);
}
return 0;
}
输出是和上面的一样的。
下面是strpbrk的另一个用处,实现和strtok相同的功能。
既然可以找到给定的字符集,那么肯定也可以用于分隔字符串了。下面的程序就实现了这个功能。
int getwords(char* words[],char* line,const char* delim){
char *pos,*pos2;
int count=0;
int k=0;
pos2=line;
while((pos=strpbrk(pos2,delim))!=NULL){
*pos='\0';//修改成'\0'主要是为了标识字符串结尾
if(pos2!=pos)
words[count++]=pos2;
pos2=pos+1;
}
if(*pos2!='\0')
words[count++]=pos2;
return count;
}
int main(){
char line[]= " ,A stringtof , ,tokensnand some more tokens , ";
char *seps = " ,\t\n";
char* words[100];
int count=getwords(words,line,seps);
int i;
for(i=0;i<count;i++)
printf("%s\n",words[i]);
}
char *pos,*pos2;
int count=0;
int k=0;
pos2=line;
while((pos=strpbrk(pos2,delim))!=NULL){
*pos='\0';//修改成'\0'主要是为了标识字符串结尾
if(pos2!=pos)
words[count++]=pos2;
pos2=pos+1;
}
if(*pos2!='\0')
words[count++]=pos2;
return count;
}
int main(){
char line[]= " ,A stringtof , ,tokensnand some more tokens , ";
char *seps = " ,\t\n";
char* words[100];
int count=getwords(words,line,seps);
int i;
for(i=0;i<count;i++)
printf("%s\n",words[i]);
}
输出如下:
需要注意的是:这个程序中和strtok一样,也对原始字符串进行了修改,将找到的一个分隔符修改为'\0'来标识字符串的结束。不然就无法知道所分隔得到的字符串是什么了。
不过也可以不对原字符串进行修改,但是这就要复制在找到一个单词的时候对这个单词进行复制到已经分配好的空间去了,这样其实效率就比较低了,所以在上面的程序中选择了修改原始的字符串。
3. strstr, strchr与strrchr
(1) 函数strstr
char * strstr ( const char *str1, const char * str2 );
功能:在str1中寻找字符串str2的第一次出现。不修改原始的字符串。
下面的一个小程序利用strstr找到了所有的出现的子字符串:
#include <stdio.h>
#include <string.h>
int getstr_pos(int *pos,const char* line,char *pat){
const char *p;
int count=0;
int len=strlen(pat);
p=line;
while((p=strstr(p,pat))!=NULL){
pos[count++]=p-line;
p+=len;
}
return count;
}
int main(){
char *str="This is a simple strisng";
char *pat="is";
int pos[20];
int count;
count=getstr_pos(pos,str,pat);
printf("%s\n",str);
if(count>0){
int i;
for(i=0;i<count;i++)
{
int j=0;
while(j<pos[i]) {
printf(" ");
j++;
}
printf("%d",pos[i]);
}
printf("\n");
}
}
#include <string.h>
int getstr_pos(int *pos,const char* line,char *pat){
const char *p;
int count=0;
int len=strlen(pat);
p=line;
while((p=strstr(p,pat))!=NULL){
pos[count++]=p-line;
p+=len;
}
return count;
}
int main(){
char *str="This is a simple strisng";
char *pat="is";
int pos[20];
int count;
count=getstr_pos(pos,str,pat);
printf("%s\n",str);
if(count>0){
int i;
for(i=0;i<count;i++)
{
int j=0;
while(j<pos[i]) {
printf(" ");
j++;
}
printf("%d",pos[i]);
}
printf("\n");
}
}
(2) 函数strchr和strrchr
char * strchr ( const char *str, int character );
char * strrchr ( const char *str, int character );
这两个函数都是用来在字符串中查找字符。
strchr是查找字符串中首次出现字符的位置,而上strrchr是查找最后一次出现
strchr的示例程序如下:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "This is a sample string";
char * pch;
printf ("Looking for the 's' character in \"%s\"...\n",str);
pch=strchr(str,'s');
while (pch!=NULL)
{
printf ("found at %d\n",pch-str+1);
pch=strchr(pch+1,'s');
}
return 0;
}
#include <string.h>
int main ()
{
char str[] = "This is a sample string";
char * pch;
printf ("Looking for the 's' character in \"%s\"...\n",str);
pch=strchr(str,'s');
while (pch!=NULL)
{
printf ("found at %d\n",pch-str+1);
pch=strchr(pch+1,'s');
}
return 0;
}
strrchr的示例程序如下:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "This is a sample string";
char * pch;
pch=strrchr(str,'s');
printf ("Last occurence of 's' found at %d \n",pch-str+1);
return 0;
}
#include <string.h>
int main ()
{
char str[] = "This is a sample string";
char * pch;
pch=strrchr(str,'s');
printf ("Last occurence of 's' found at %d \n",pch-str+1);
return 0;
}
4. 字符串与数值之间的转换
C语言主要提供了如下几个转换函数:
atof(); 将字符串转换成浮点型数
atoi(); 将字符串转换成整型数
atol(); 将字符串转换成长整型数
strtod(); 将字符串转换成浮点数
strtol(); 将字符串转换成长整型数
strtoul(); 将字符串转换成无符号长整型数
(1) strtod函数
double strtod ( const char * str, char ** endptr );
对于strtod来说合法的输入:
#An optional plus or minus sign
#A sequence of digits, optionally containing a decimal-point character
#An optional exponent part, which itself consists on an 'e' or 'E' character followed by an optional sign and a sequence of digits.
endptr保存是下一个解析得到的数值之后的下一个字符指针
一个简单的示例程序如下:
#include <stdio.h>
#include <stdlib.h>
int main ()
{
char szOrbits[] = "365.24 29.53";
char * pEnd;
double d1, d2;
d1 = strtod (szOrbits,&pEnd);
d2 = strtod (pEnd,NULL);
printf ("The moon completes %.2lf orbits per Earth year.\n", d1/d2);
return 0;
}
#include <stdlib.h>
int main ()
{
char szOrbits[] = "365.24 29.53";
char * pEnd;
double d1, d2;
d1 = strtod (szOrbits,&pEnd);
d2 = strtod (pEnd,NULL);
printf ("The moon completes %.2lf orbits per Earth year.\n", d1/d2);
return 0;
}
(2) 函数strtol
long int strtol ( const char * str, char ** endptr, int base );
对于strtol来说合法输入:
#An optional plus or minus sign
#An optional prefix indicating octal or hexadecimal base ("0" or "0x" respectively)
#A sequence of decimal digits (if no base prefix was specified) or either octal or hexadecimal digits if a specific prefix is present
一个示例小程序如下:
#include <stdio.h>
#include <stdlib.h>
int main ()
{
char szNumbers[] = "2001 60c0c0 -1101110100110100100000 0x6fffff";
char * pEnd;
long int li1, li2, li3, li4;
li1 = strtol (szNumbers,&pEnd,10);
li2 = strtol (pEnd,&pEnd,16);
li3 = strtol (pEnd,&pEnd,2);
li4 = strtol (pEnd,NULL,0);
printf ("The decimal equivalents are: %ld, %ld, %ld and %ld.\n", li1, li2, li3, li4);
return 0;
}
#include <stdlib.h>
int main ()
{
char szNumbers[] = "2001 60c0c0 -1101110100110100100000 0x6fffff";
char * pEnd;
long int li1, li2, li3, li4;
li1 = strtol (szNumbers,&pEnd,10);
li2 = strtol (pEnd,&pEnd,16);
li3 = strtol (pEnd,&pEnd,2);
li4 = strtol (pEnd,NULL,0);
printf ("The decimal equivalents are: %ld, %ld, %ld and %ld.\n", li1, li2, li3, li4);
return 0;
}
(3) 函数strtoul
unsigned long int strtoul ( const char * str, char ** endptr, int base );
合法输入如下:
#An optional prefix indicating octal or hexadecimal base ("0" or "0x" respectively)
#A sequence of decimal digits (if no base prefix was specified) or either octal or hexadecimal digits if a specific prefix is present
示例小程序如下:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a;
char pNum[]="0xFF";
a=strtoul(pNum,0,16);
printf("%d\n",a);
return 0;
}
#include <stdlib.h>
int main()
{
int a;
char pNum[]="0xFF";
a=strtoul(pNum,0,16);
printf("%d\n",a);
return 0;
}
(4)函数atoi
int atoi ( const char * str );
示例程序如下:
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int i;
char szInput [256];
printf ("Enter a number: ");
fgets ( szInput, 256, stdin );
i = atoi (szInput);
printf ("The value entered is %d. The double is %d.\n",i,i*2);
return 0;
}
#include <stdlib.h>
int main ()
{
int i;
char szInput [256];
printf ("Enter a number: ");
fgets ( szInput, 256, stdin );
i = atoi (szInput);
printf ("The value entered is %d. The double is %d.\n",i,i*2);
return 0;
}
(5)函数atol
long int atol ( const char * str );
示例程序如下:
#include <stdio.h>
#include <stdlib.h>
int main ()
{
long int li;
char szInput [256];
printf ("Enter a long number: ");
gets ( szInput );
li = atol (szInput);
printf ("The value entered is %d. The double is %d.\n",li,li*2);
return 0;
}
#include <stdlib.h>
int main ()
{
long int li;
char szInput [256];
printf ("Enter a long number: ");
gets ( szInput );
li = atol (szInput);
printf ("The value entered is %d. The double is %d.\n",li,li*2);
return 0;
}
(6)函数atof
double atof ( const char * str );
示例程序如下:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main ()
{
double n,m;
double pi=3.1415926535;
char szInput [256];
printf ( "Enter degrees: " );
gets ( szInput );
n = atof ( szInput );
m = sin (n*pi/180);
printf ( "The sine of %f degrees is %f\n" , n, m );
return 0;
}
#include <stdlib.h>
#include <math.h>
int main ()
{
double n,m;
double pi=3.1415926535;
char szInput [256];
printf ( "Enter degrees: " );
gets ( szInput );
n = atof ( szInput );
m = sin (n*pi/180);
printf ( "The sine of %f degrees is %f\n" , n, m );
return 0;
}
5. frexp和ldexp
(1)函数frexp
double frexp (double x, int * exp );
功能:标准化浮点数, f=x*2^p, 已知f求x, p (x介于[0.5, 1] )
返回值为尾数,*exp是指数
示例程序如下:
#include <stdio.h>
#include <math.h>
int main ()
{
double param, result;
int n;
param = 8.0;
result = frexp (param , &n);
printf ("%lf * 2^%d = %f\n", result, n, param);
return 0;
}
#include <math.h>
int main ()
{
double param, result;
int n;
param = 8.0;
result = frexp (param , &n);
printf ("%lf * 2^%d = %f\n", result, n, param);
return 0;
}
输出:
0.500000 * 2^4 = 8.000000
(2)函数ldexp
double ldexp(double x, int exp );
功能:与frexp相反, 已知x, p求f
示例如下:
#include <stdio.h>
#include <math.h>
int main ()
{
double param, result;
int n;
param = 0.95;
n = 4;
result = ldexp (param , n);
printf ("%f * 2^%d = %f\n", param, n, result);
return 0;
}
#include <math.h>
int main ()
{
double param, result;
int n;
param = 0.95;
n = 4;
result = ldexp (param , n);
printf ("%f * 2^%d = %f\n", param, n, result);
return 0;
}
输出:
0.950000 * 2^4 = 15.200000