数值(double)转中文输出

摘要

本文讲述1亿以内的double类型转为中文字符串示例,该示例难点在于double类型精度处理。

代码

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>

#define INTEGER_UINT_LEN 5 //1亿以内:万/千/百/十/个
#define DECIMAL_UINT_LEN 2 // 2位小数
#define PER_UINT_SIZE 3 // 单个汉子长度

static inline int IntegerToText(unsigned int u32Value, char *szText) {
    char szValue[128] = {0};
    unsigned short u16Idx = 0;
    unsigned int u32Offset = 0;
    char *szNumStr[10] = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};

    if (u32Value >= 10000) {
        printf("OverMaxUnitLength:xxxx\n");
        return -1;
    }

    while (u32Value > 0) {
        szValue[u16Idx++] = u32Value % 10;
        u32Value = u32Value / 10;
    }

    if (u16Idx == 4) { // XXXX
        // X---
		memcpy((szText + u32Offset), szNumStr[szValue[u16Idx - 1]], PER_UINT_SIZE);
		u32Offset += PER_UINT_SIZE;
        sprintf(&szText[u32Offset], "%s", "千");
		u32Offset += PER_UINT_SIZE;

        // X--
        if (szValue[u16Idx - 2]) {
            memcpy((szText + u32Offset), szNumStr[szValue[u16Idx - 2]], PER_UINT_SIZE);
			u32Offset += PER_UINT_SIZE;
            sprintf(&szText[u32Offset], "%s", "百");
			u32Offset += PER_UINT_SIZE;
        } else {
            sprintf(&szText[u32Offset], "%s", "零");
			u32Offset += PER_UINT_SIZE;
        }
        // X-
        if (szValue[u16Idx - 3]) {
            memcpy((szText + u32Offset), szNumStr[szValue[u16Idx - 3]], PER_UINT_SIZE);
			u32Offset += PER_UINT_SIZE;
            sprintf(&szText[u32Offset], "%s", "十");
			u32Offset += PER_UINT_SIZE;
        } else {
            sprintf(&szText[u32Offset], "%s", "零");
			u32Offset += PER_UINT_SIZE;
        }
        // X
        if (szValue[u16Idx - 4]) {
            memcpy((szText + u32Offset), szNumStr[szValue[u16Idx - 4]], PER_UINT_SIZE);
			u32Offset += PER_UINT_SIZE;
        }
    } else if (u16Idx == 3) { // XXX
        // X--
        memcpy((szText + u32Offset), szNumStr[szValue[u16Idx - 1]], PER_UINT_SIZE);
		u32Offset += PER_UINT_SIZE;
        sprintf(&szText[u32Offset], "%s", "百");
		u32Offset += PER_UINT_SIZE;

        // X-
        if (szValue[u16Idx - 2]) {
            memcpy((szText + u32Offset), szNumStr[szValue[u16Idx - 2]], PER_UINT_SIZE);
			u32Offset += PER_UINT_SIZE;
            sprintf(&szText[u32Offset], "%s", "十");
			u32Offset += PER_UINT_SIZE;
        } else {
            sprintf(&szText[u32Offset], "%s", "零");
			u32Offset += PER_UINT_SIZE;
        }
        // X
        if (szValue[u16Idx - 3]) {
            memcpy((szText + u32Offset), szNumStr[szValue[u16Idx - 3]], PER_UINT_SIZE);
			u32Offset += PER_UINT_SIZE;
        }
    } else if (u16Idx == 2) { // XX
        // X-
        memcpy((szText + u32Offset), szNumStr[szValue[u16Idx - 1]], PER_UINT_SIZE);
		u32Offset += PER_UINT_SIZE;
        sprintf(&szText[u32Offset], "%s", "十");
		u32Offset += PER_UINT_SIZE;

        // X
        if (szValue[u16Idx - 2]) {
            memcpy((szText + u32Offset), szNumStr[szValue[u16Idx - 2]], PER_UINT_SIZE);
			u32Offset += PER_UINT_SIZE;
        }
    } else if (u16Idx == 1) { // X
        memcpy((szText + u32Offset), szNumStr[szValue[u16Idx - 1]], PER_UINT_SIZE);
		u32Offset += PER_UINT_SIZE;
    } else {
        sprintf(&szText[u32Offset], "%s", "零");
		u32Offset += PER_UINT_SIZE;
    }

    return u32Offset;
}

static inline int DecimalToText(double f64Value, char *szText) {
    char szValue[DECIMAL_UINT_LEN] = {0};
    unsigned short u16Idx = 0;
    unsigned int u32Offset = 0;
	unsigned int u32Decimal = 0;
	unsigned int u32Precision = 0;
	unsigned int u32Base = 0;
	unsigned int u32Integer = 0;
    char *szNumStr[10] = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};

    // 基准放大倍数,通过放大将小数转为整数
	u32Base = pow(10, DECIMAL_UINT_LEN);
	u32Integer = (unsigned int)f64Value;
    // 基准放大倍数基础上,再放大10倍,用于精度保留,
    // (u32Base * 10) 一定要加上括号,要确保浮点型运算一次性放大,
    // 如果f64Value * u32Base * 10, 仍然会引起精度丢失(截断:比如19.99->19.98)
	u32Decimal = (unsigned int)(f64Value * (u32Base * 10) - u32Integer * (u32Base * 10));
    u32Decimal /= 10;

    printf("#DecimaToText: Target:%lf, Base:%d, Interger:%u, Decimal:%u\n",
           f64Value, u32Base, u32Integer, u32Decimal);

	u32Base /= 10;
	for (int i = 0; i < DECIMAL_UINT_LEN; i++) {
		if ((i == (DECIMAL_UINT_LEN - 1)) && u32Decimal) {
			szValue[u16Idx++] = u32Decimal;
			break;
		}

		if (u32Decimal < u32Base) {
			szValue[u16Idx++] = 0;
		} else {
			szValue[u16Idx++] = u32Decimal / u32Base;
			u32Decimal = u32Decimal % u32Base;
			if (u32Decimal == 0)
				break;
		}

		u32Base /= 10;
	}

    if (!u16Idx)
        return 0;

    sprintf(&szText[u32Offset], "%s", "点");
	u32Offset += PER_UINT_SIZE;
    for (unsigned short i = 0; i < u16Idx; i++) {
        memcpy((szText + u32Offset), szNumStr[szValue[i]], PER_UINT_SIZE);
		u32Offset += PER_UINT_SIZE;
	}

    return u32Offset;
}

static inline int DoubleToText(double f64Target, char *szText) {
    unsigned int u32Integer;
    unsigned int u32Offset;
    unsigned int u32Tmp;
    int s32Ret = 0;
    bool bActive = false;
	char *szUintStr[INTEGER_UINT_LEN] = {"万", "千", "百", "十", NULL};
	unsigned int szUintValue[INTEGER_UINT_LEN] = {10000, 1000, 100, 10, 0};

    if (f64Target >= 100000000.0f) {
        printf("OverMaxValue:100000000.0f\n");
        return -1;
    }

	u32Offset = 0;
    u32Integer = (unsigned int)f64Target;

	// 整数部分转为字符串
	for (int i = 0; i < INTEGER_UINT_LEN; i++) {
		// 个位数特殊处理
		if (i == (INTEGER_UINT_LEN - 1)) {
			s32Ret = IntegerToText(u32Integer, szText + u32Offset);
			if (s32Ret < 0)
				return -1;

			u32Offset += s32Ret;
			break;
		}

		// 十位数及以上位数处理
		if (u32Integer < szUintValue[i]) {
			if (bActive) {
				sprintf(&szText[u32Offset], "%s", "零");
				u32Offset += PER_UINT_SIZE;
			}
		} else {
			u32Tmp = u32Integer / szUintValue[i];
			u32Integer = u32Integer % szUintValue[i];
			s32Ret = IntegerToText(u32Tmp, szText + u32Offset);
			if (s32Ret < 0)
				return -1;

			u32Offset += s32Ret;
			sprintf(&szText[u32Offset], "%s", szUintStr[i]);
			u32Offset += PER_UINT_SIZE;
			bActive = true;
			if (u32Integer == 0)
				break;
		}
	}

	// 小数位处理
	if (f64Target > u32Integer) {
		s32Ret = DecimalToText(f64Target, szText + u32Offset);
		if (s32Ret < 0)
            return -1;
		u32Offset += s32Ret;
	}

	// return total size
    return u32Offset;
}

int main() 
{
	double f64Value = 0.0f;
	char szText[1024] = {0};

	while (1) {
		printf("#Please input num(double):\n");
		scanf("%lf", &f64Value);
		memset(szText, 0, sizeof(szText));
		DoubleToText(f64Value, szText);
		printf("Resutl:%f -> %s\n", f64Value, szText);
	}

	return 0;
}


编译

gcc 直接编译,连接数学库,形如:gcc -o test test.c -lm

结果展示

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值