字符转换

今天开始写那个主成分分析的程序。
GUI采用wxWidget。内部用unicode编码。
本来我准备用gmp作高精度库的,但是我重装了系统换了vc8,然后才发现gmp根本就不支持win,以前的那个,是我在一个网友的基础上,在vc71下hack的gmp4.1,gmp最新的版本是4.2.要我重新hack一次吗?算了,没时间。于是找啊找,就用了NTL.

NTL编译后居然有80多M,真大。

NTL的一个缺点是输入输出接口的匮乏,只支持从iostream读入、输出。还有就是有几个全局函数是在指定的精度下对char*做输入输出。共同的缺点就是不支持wchar_t.

然后今天就陷入字符转换的hell中了。

昨天有人在smth上问如何把数字转换为字符串,这原本不是问题的一个问题,其实后面复杂着呢。要想做正确的转换,就必须依赖于locale,然后……然后……hell啊~

同样,从wchar_t*到char*的转换也是,必须依赖于locale.

我本来不想转,我觉得无非就是指针嘛。wxString内部用的是unicode(not
utf8!!!),uft8和ascii是兼容的,反正我只处理数字,还转它做什么。于是就没有理会。

结果是运行很正常。我输入几个整数,计算下平均值和方差,oh,yeah! 一切都对。可是当我计算实际数据的时候,发现精度丢失。求和的结果是整数。我很纳闷……

后来发现精度问题居然是发生在了字符转换上。由于wchar_t是双字节,原来的"ab"这样的字符串在wchar_t的存储下就是"a.b.",然后我没有注意。其实每次从stream中把字符串输入的时候我只输入了第一个字符,第二个字符因为是0所以后面的都被略掉了。我刚开始的测试数据恰好都是单位的整数,所以就没有发现。

类似的错误还有,在locale未设置或者设置错误的情况下,做字符转换的时候,通常第一个字符会被转错,然后后面的字符都是正确的。很常见的例子就是在菜单栏或者其它的地方我们常会看见这样的一些字符串,它的第一个字是乱码,但是后面的都是正常显示的中文字符。

然后我自己写了个转换函数,就好了。

当然,问题还没有完,我计算出的结果,和maple的结果,和excel的计算结果,相差甚大。我和maple的比较接近。

我无法确定问题是出在了精度上还是我的算法还有错误。我觉得两者的可能性都不大。因为我的精度肯定要比maple默认的高,而我的算法如果存在错误的话,误差不会这么小,在5%以下。

however,今天晚上又是一场讲座,不可错过,不可错过……

///用于将wchar_t*转换为char*的小函数。
inline char* conv_string(const wchar_t* pszExt){
    size_t pszExt_len=wcslen(pszExt);
    size_t len=2*pszExt_len+8;
    char* buf=new char[len+1];
    memset(buf,0,len+1);
    const wchar_t* pszNext;
    char* pwszNext;
    mbstate_t state;

    int res = std::use_facet<std::codecvt<wchar_t, char, mbstate_t> >
    ( std::locale() ).out( state,
    pszExt, &pszExt[pszExt_len], pszNext,
    buf, buf+pszExt_len, pwszNext );
    //buf.get()[strlen(pszExt)] = 0;
    pwszNext[1]='\0';
    switch(res){
    case std::codecvt_base::error:
        return NULL;
    case std::codecvt_base::noconv:
        buf[0]='\0';
        return buf;
    case std::codecvt_base::ok:
        return buf;
    case std::codecvt_base::partial:
        return buf;
    default:
        return NULL;
    }
}

此博客中的热门博文

少写代码,多读别人写的代码

在windows下使用llvm+clang

tensorflow distributed runtime初窥