在不截断或精度损失的情况下删除 ascii 浮点数中的小数点
remove decimal point in ascii float number without truncating or precision loss
我有一个代表电压的ascii浮点数,例如。 5.625V,我需要去掉小数点。我不想截断数字或降低精度我只需要没有小数点的数字。
结果数字将被插入到 ascii 协议中,其字段宽度为 5 位长度,表示电压,单位为 mV(毫伏)与 V(伏特),如上例所示。数字需要显示为5位ascii数字,无十进制。
例如。 5.625V ascii 浮点数到 5625 mV ascii 十进制数..
看起来很简单...但无法找到一种优雅的方式来做到这一点。
只转换毫伏数,不带小数部分:
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_MAX
的 float
时出现未定义的行为。 long long
保证至少为 64 位。相应地调整 printf
格式说明符。
请注意,如果值超出 int
的范围,则转换为 int
会向 0
舍入并调用未定义的行为。如果您知道您的值为正且在范围内,则可以使用 (int)(value * 1000 + 0.5)
获得更高的准确性
问题提示输入的是 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
我有一个代表电压的ascii浮点数,例如。 5.625V,我需要去掉小数点。我不想截断数字或降低精度我只需要没有小数点的数字。
结果数字将被插入到 ascii 协议中,其字段宽度为 5 位长度,表示电压,单位为 mV(毫伏)与 V(伏特),如上例所示。数字需要显示为5位ascii数字,无十进制。
例如。 5.625V ascii 浮点数到 5625 mV ascii 十进制数..
看起来很简单...但无法找到一种优雅的方式来做到这一点。
只转换毫伏数,不带小数部分:
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_MAX
的 float
时出现未定义的行为。 long long
保证至少为 64 位。相应地调整 printf
格式说明符。
请注意,如果值超出 int
的范围,则转换为 int
会向 0
舍入并调用未定义的行为。如果您知道您的值为正且在范围内,则可以使用 (int)(value * 1000 + 0.5)
问题提示输入的是 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