SAS 程序冷知识——保留小数与保留有效数字,兼论数值与字符互换对结果的损失

最近经常被一个问题苦恼,就是sas在保留小数位的时候经常会出错,我个人偏爱put,但put有的时候会出问题。所以我想,在保留时如果先把小数位放开到最多,然后先变字符型再变回数值,就可以有效保证put后不会出问题。

但如果这样改的话会很麻烦,因为我已经有很多写好的宏,于是考虑是否可以用自定义函数。这样,只要新函数的参数和put保持一致,就可以通过全文替换,直接完成修改。经过测试,自定义函数可以用语sql,这是个好事。

想起之前我写过一个保留有效数字的方法,突然想不如一起集合在一个函数上,于是新函数设计了3个参数,前两个和put一样。第三个参数如果是0则为保留小数,如果是1则是保留有效数字。当参数为1时,第二个参数只能是正整数。

proc fcmp outlib=work.funcs.putd;

    /* 定义函数 */

    function putd(var, informat , roundOption) $200;

        length result $200; /* 假设转换后的字符不会超过200个字符 */

/* informat 参数应转换为SAS格式名称 */

        formatName = cats(informat);

        /* 根据 roundOption 的值处理变量 */

        if roundOption = 0 then do;

            result = cats(putn(round(var,0.1**30), formatName)); /* 四舍五入 informat为数值型*/

        end;

        else if roundOption = 1 then do;/* 保留有效数字 informat为正整数*/

            length ornumc $200;

            if int(var)^=var then ornumc=strip(put(var,best.));

            else ornumc=cats(put(var,best.),'.');

            dot=index(strip(ornumc),'.');

            efb=prxmatch('/[1-9]/',strip(ornumc));

            efe=efb+informat;

            if efb < dot <= efe then efe=efe+1;

            if efe > dot > 1  then result=putn(var,cats('30.',efe-dot-1,'-l'));

            else if  dot > 1 then result=strip(putn(round(var,10**(dot-1-informat)),cats('32.',formatName)));

        end;

        else do;

            result = 'Invalid Option'; /* 无效的选项 */

        end;

        return(result); /* 返回结果 */

    endsub;

run;

quit;

/* 从编译的函数库中引用函数 */

options cmplib=(work.funcs);

data _null_ aaaa;

    num_var = 123.456; /* 测试的数值 */

    char_var = putd(num_var, 12.1, 0); /* 调用函数进行转换 */

    put char_var=; /* 输出转换结果 */

run;

本来想把putd函数的第3个参数设默认值的,后来发现无法设定。所以我自己已经把上面这个拆成2个函数了。大家看自己需要吧。

再有就是这段程序会在work下生成一个名为Funcs的数据集,这个数据集存在,才可以使用新函数。建议定义的时候把这个数据集定义到一个其他逻辑库下,这样可以防止被误删。

************************************************************************************************

需要补充一点,本来我在下面一步中,打算使用put的:先用put变成字符,然后再用input换成数值,目的是先保留一个比较多的位数,然后在此基础上保留正确小数位。

result = cats(putn(round(var,0.1**30), formatName)); /* 四舍五入 informat为数值型*/

但是这个代码却有致命问题:

当数值和字符互换的时候,数值会发生损失,请看下面例子:

data _null_;

a=2.25;

b=put(a,32.25);

c=input(b,best32.);

d=a-b;

e=a=b;

f=a-c;

g=a=c;

put a=b=c=d=e=f=g=;

run;

结果为:A=2.25 B=2.2500000000000000000000000 C=2.25 D=4.440892E-16 E=0 F=4.440892E-16 G=0

可以看到,2.25通过put变成字符,再换回数值后,与原来的2.25相比,差值(F的值)不为0。这种情况原因不明,但可以肯定,会发生在本来小数位不多,但放出小数位很多的情况下。上例中,如果把b=put(a,32.25);换成b=put(a,32.24);,则F的值就会变成0,也就是说在2.25这个数中,25位就是一个极限值 。

但是极限值和数值有关,如果把2.25换掉,则这个极限值也会改变。但两者关系目前并不清楚,有机会我再测试一下。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容