【问题标题】:remove decimal point in ascii float number without truncating or precision loss [closed]删除 ascii 浮点数中的小数点而不截断或精度损失[关闭]
【发布时间】:2016-01-29 09:34:16
【问题描述】:

我在 ascii 中有一个浮点数,表示电压,例如。 5.625V,我需要去掉小数点。我不想截断数字或松散的精度,我只需要不带小数点的数字。

生成的数字将插入到 ascii 协议中,字段宽度为 5 位长度,表示电压,单位为 mV(毫伏)vs V(伏),如上例所示。数字需要显示为 5 位 ascii 数字,没有十进制。

例如。 ascii中的5.625V浮点数到ascii中的5625 mV十进制数..

看起来很简单......但无法找到一种优雅的方式来做到这一点。

【问题讨论】:

  • 将结果乘以 10000 并以整数形式发送将解决我认为的问题
  • printf("%f V is %5d mV", voltage, voltage*1000);
  • '我在 ascii 中有一个浮点数,表示电压,例如。 5.625V' - 这是否意味着带有空终止符的 C 样式字符串,即。 “5.625V”?您的问题似乎暗示了这一点,但一些 cmets/answers 表明它是某种格式的“真实 FP 值,例如。单人或双人。是哪个?
  • @shark.....第二个参数没有显示值,输出显示..“3.968346 V is 0 mV”
  • @Shark,如果voltage 是浮点数,那么voltage*1000 也是浮点数。

标签: c floating-point printf string-formatting decimal-point


【解决方案1】:

只转换毫伏数,不带小数部分:

char buffer[32];
float voltage = 5.625;

snprintf(buffer, sizeof buffer, "%.0f", voltage * 1000.);

如果您想用空格填充 5 个字符,并且您知道毫伏数适合 int,您可以使用:

snprintf(buffer, sizeof buffer, "%5d", (int)(voltage * 1000));

如果您应该使用前导零填充 5 个字符,请使用:

snprintf(buffer, sizeof buffer, "%05d", (int)(voltage * 1000));

如果您平台上的int 仅具有16 位,则在转换超过INT_MAXfloat 时应使用更大的类型以避免未定义的行为。 long long 保证至少为 64 位。相应地调整printf 格式说明符。

请注意,转换为int 会向0 舍入,如果值超出int 的范围,则会调用未定义的行为。如果你知道你的值是正的并且在范围内,你可以通过(int)(value * 1000 + 0.5)获得更好的准确度

【讨论】:

  • 如果是 5 位,那么也许你想乘以 10,000。但是单位会出错,我明白了...... :(
  • @lan:数字以毫伏为单位,最好用空格填充。
  • 是的,我也注意到了这一点。它本质上不匹配:5位和x1000 ...
  • 用前导零填充。
  • @Ian:只要范围达到 99.999V,它就可以匹配。
【解决方案2】:

问题表明输入是一个 ASCII 字符串,所以我想出了这个:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

long s2mv(const char *s)
{
    long mv;
    char *end;
    int sign;

    while (isspace((unsigned char)*s)) {
        s++;
    }

    sign = (*s == '-') ? -1 : 1;
    if (*s == '-' || *s == '+') {
        s++;
    }

    mv = 1000 * strtol(s, &end, 10);
    s = end;
    if (*s++ == '.') {
        int place = 100;

        while (place && isdigit((unsigned char)*s)) {
            mv += place * (*s - '0');
            s++;
            place /= 10;
        }
    }
    return mv * sign;
}

int main(void)
{
    const char *tests[] = {
        "0", "12", "-12", "12.", "-12.", "12.345", "-12.345",
        "1.234", ".123", "0.123", "-0.123", "-.123"
    };
    long mv;
    int i;

    for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
        mv = s2mv(tests[i]);
        printf("s2mv(\"%s\") returned %ld\n", tests[i], mv);
    }
    return 0;
}

输出:

s2mv("0") returned 0
s2mv("12") returned 12000
s2mv("-12") returned -12000
s2mv("12.") returned 12000
s2mv("-12.") returned -12000
s2mv("12.345") returned 12345
s2mv("-12.345") returned -12345
s2mv("1.234") returned 1234
s2mv(".123") returned 123
s2mv("0.123") returned 123
s2mv("-0.123") returned -123
s2mv("-.123") returned -123

【讨论】:

  • 你说的完全正确!根本不需要浮点运算。我删除了*s 上的测试,因为isspace()isdigit() 保证为'\0' 返回0。
  • 我猜这两个答案都很有用,因为问题提到毫伏值将作为 5 位 ASCII 字符串插入协议中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-09
  • 2018-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-01
相关资源
最近更新 更多