我想从一个双精度点上打印一个以分钟和秒为单位的时间,包括它们的小数部分,最多6位,并且不带尾随零。
由于格式的性质,应该有可能在单个printf()
语句中将解决方案嵌套在其他参数中!
我要打印的时间变量是秒单位的两倍,并且不超过几十小时的范围。
double time1 = 123.456789; // 2:03.456789 some text
double time2 = 12345.6; // 205:45.6 some text
printf("format: %-16s time1: %.6g some text\n", "%.6g", time1);
printf("format: %-16s time2: %.6g some text\n", "%.6g", time2);
printf("format: %-16s time1: %3d:%09.6f some text\n", "%3d:%09.6f", (int)time1 / 60, fmod(time1, 60));
printf("format: %-16s time2: %3d:%09.6f some text\n", "%3d:%09.6f", (int)time2 / 60, fmod(time2, 60));
printf("format: %-16s time1: %3d:%09.6g some text\n", "%3d:%09.6g", (int)time1 / 60, fmod(time1, 60));
printf("format: %-16s time2: %3d:%09.6g some text\n", "%3d:%09.6g", (int)time2 / 60, fmod(time2, 60));
printf("format: %-16s time1: %3d:%0.6g some text\n", "%3d:%0.6g", (int)time1 / 60, fmod(time1, 60));
printf("format: %-16s time2: %3d:%0.6g some text\n", "%3d:%0.6g", (int)time2 / 60, fmod(time2, 60));
printf("format: %-16s time1: %3d:%02d%.6f some text\n", "%3d:%02d%.6f", (int)time1 / 60, (int)time1 % 60, fmod(time1, 1));
printf("format: %-16s time2: %3d:%02d%.6f some text\n", "%3d:%02d%.6f", (int)time2 / 60, (int)time2 % 60, fmod(time2, 1));
printf("format: %-16s time1: %3d:%02d%.6g some text\n", "%3d:%02d%.6g", (int)time1 / 60, (int)time1 % 60, fmod(time1, 1));
printf("format: %-16s time2: %3d:%02d%.6g some text\n", "%3d:%02d%.6g", (int)time2 / 60, (int)time2 % 60, fmod(time2, 1));
printf("format: %-16s time1: %3d:%02d%0.6g some text\n", "%3d:%02d%0.6g", (int)time1 / 60, (int)time1 % 60, fmod(time1, 1));
printf("format: %-16s time2: %3d:%02d%0.6g some text\n", "%3d:%02d%0.6g", (int)time2 / 60, (int)time2 % 60, fmod(time2, 1));
预期:
time1: 2:03.456789 some text
time2: 205:45.6 some text
结果:
format: %.6g time1: 123.457 some text
format: %.6g time2: 12345.6 some text
format: %3d:%09.6f time1: 2:03.456789 some text <- OK
format: %3d:%09.6f time2: 205:45.600000 some text <- trailing zeros
format: %3d:%09.6g time1: 2:003.45679 some text <- 3 digits for minutes, missing 8
format: %3d:%09.6g time2: 205:0000045.6 some text <- 7 digits for minutes
format: %3d:%0.6g time1: 2:3.45679 some text <- 1 digit for minutes, missing 8
format: %3d:%0.6g time2: 205:45.6 some text <- OK
format: %3d:%02d%.6f time1: 2:030.456789 some text <- leading 0
format: %3d:%02d%.6f time2: 205:450.600000 some text <- leading 0, trailing zeros
format: %3d:%02d%.6g time1: 2:030.456789 some text <- leading 0
format: %3d:%02d%.6g time2: 205:450.6 some text <- leading 0
format: %3d:%02d%0.6g time1: 2:030.456789 some text <- leading 0
format: %3d:%02d%0.6g time2: 205:450.6 some text <- leading 0
另一种格式会很好:
time2: 3:25:45.6 some text
答案 0 :(得分:5)
对于正时间值,请尝试以下格式:
main
但是请注意,如果分数值大于或等于printf("%d:%d%g\n",
(int)time / 60, // number of minutes
(int)time % 60 / 10, // number of tens of seconds
time - (int)time / 10 * 10); // number of seconds units and fraction thereof
,这将不起作用,因为最后一项将舍入到下一个整数。
将时间转换为整数微秒并以这种方式打印会更安全:
0.9999995
用这种方法去除尾随零会更麻烦,恐怕使用函数会更好。正确处理无限值和nan等极端情况并保持正确的舍入是很难的。
这是一个带有测试程序的示例:
int us = (int)(time * 1000000 + 0.5);
printf("%d:%02d.%06d\n", us / 60000000, us / 1000000 % 60, us % 1000000);
输出:
0 --> 0:00 -0 --> -0:00 1 --> 0:01 -1 --> -0:01 59 --> 0:59 -59 --> -0:59 60 --> 1:00 -60 --> -1:00 61 --> 1:01 -61 --> -1:01 121.1 --> 2:01.1 -121.1 --> -2:01.1 121.11 --> 2:01.11 -121.11 --> -2:01.11 121.111 --> 2:01.111 -121.111 --> -2:01.111 121.1111 --> 2:01.1111 -121.1111 --> -2:01.1111 121.11111 --> 2:01.11111 -121.11111 --> -2:01.11111 121.111111 --> 2:01.111111 -121.111111 --> -2:01.111111 4321 --> 72:01 -4321 --> -72:01 12345.6 --> 205:45.6 -12345.6 --> -205:45.6 123.456789 --> 2:03.456789 -123.456789 --> -2:03.456789 129.9999994 --> 2:09.999999 -129.9999994 --> -2:09.999999 129.9999995 --> 2:10 -129.9999995 --> -2:10 599.9999994 --> 9:59.999999 -599.9999994 --> -9:59.999999 599.9999994999999 --> 9:59.999999 -599.9999994999999 --> -9:59.999999 599.99999951 --> 10:00 -599.99999951 --> -10:00 599.9999999 --> 10:00 -599.9999999 --> -10:00 23.9999999999 --> 0:24 -23.9999999999 --> -0:24 59.9999994 --> 0:59.999999 -59.9999994 --> -0:59.999999 59.9999996 --> 1:00 -59.9999996 --> -1:00 999.0000005000001 --> 16:39.000001 -999.0000005000001 --> -16:39.000001 1000.0000005 --> 16:40.000001 -1000.0000005 --> -16:40.000001 999.9999999 --> 16:40 -999.9999999 --> -16:40 1000000 --> 16666:40 -1000000 --> -16666:40 10000000000 --> 166666666:40 -10000000000 --> -166666666:40 1000000000000 --> 16666666666:40 -1000000000000 --> -16666666666:40 1000000000000000 --> 16666666666666:40 -1000000000000000 --> -16666666666666:40 1e+18 --> 16666666666666666:40 -1e+18 --> -16666666666666666:40 1e+20 --> 1666666666666666752:40 -1e+20 --> -1666666666666666752:40 1e+25 --> 166666666666666697424896:04 -1e+25 --> -166666666666666697424896:04 1e+30 --> 16666666666666666704873979904:16 -1e+30 --> -16666666666666666704873979904:16 128849018820 --> 2147483647:00 -128849018820 --> -2147483647:00 128849020054 --> 2147483667:34 -128849020054 --> -2147483667:34 1.180591620717411e+21 --> 19676527011956854784:04 -1.180591620717411e+21 --> -19676527011956854784:04 1.797693134862316e+308 --> 2996155224770526471302168869341711813188863443303040828151933426890179148788615168103226874770040896498710950234612783266345520226229959458788332419124700807563385759480436831271585473539816641208848852443854529842024245861042631496840000693995654184204690418742185022600768539063077737531453954861570195456:08 -1.797693134862316e+308 --> -2996155224770526471302168869341711813188863443303040828151933426890179148788615168103226874770040896498710950234612783266345520226229959458788332419124700807563385759480436831271585473539816641208848852443854529842024245861042631496840000693995654184204690418742185022600768539063077737531453954861570195456:08 inf --> inf -inf --> -inf nan --> nan nan --> nan
答案 1 :(得分:1)
我想从一个双精度点上打印一个以分钟和秒为单位的时间,包括它们的小数部分,最多6位,并且不带尾随零。
具有挑战性的部分是将double
转换为文本时发生的舍入。
以下代码将时间四舍五入为x.dddddd秒,然后重整秒数。
代码已针对边缘条件进行了测试。
#include <math.h>
#include <stdio.h>
int print_msf(double time_in_seconds, const char *suffix) {
// print as seconds and a fraction - value rounded to nearest 0.000001
// - 308 1 . 000000 \0
char buf[1 + (DBL_MAX_10_EXP + 1) + 1 + 6 + 1];
sprintf(buf, "%.6f", time_in_seconds);
int dp = '.'; // adjust for other locales if needed
char *dpp = strchr(buf, dp);
if (dpp == NULL) {
return printf("%s%s\n", buf, suffix); // infinity or NaN
} else {
int significant_digs = 6;
while (dpp[significant_digs] == '0') {
significant_digs--;
}
dpp[1 + significant_digs] = '\0';
*dpp = '\0';
double t = atof(buf); // rounded whole number
const char *sign = signbit(t) ? "-" : "";
t = fabs(t);
double seconds = fmod(t, 60);
double minutes = (t - seconds) / 60;
if (minutes) {
seconds = fabs(seconds);
}
return printf("%s%.0f:%02.0f.%s%s\n", sign, minutes, seconds, dpp + 1,
suffix);
}
}
#include <float.h>
#include <limits.h>
int main(void) {
//double time1 = 123.456789; // 2:03.456789 some text
//double time2 = 12345.6; // 205:45.6 some text
double t[] = {123.456789, 12345.6, -0.0, 59.9999994, 59.9999996,
(double) ULLONG_MAX * 64.0, DBL_MAX, 1.0 / 0.0, NAN};
size_t n = sizeof t / sizeof t[0];
for (size_t i = 0; i < n; i++) {
printf("%30.16e --> ", t[i]);
print_msf(t[i], " some text");
printf("%30.16e --> ", -t[i]);
print_msf(-t[i], " some text");
}
return 0;
}
输出
1.2345678900000000e+02 --> 2:03.456789 some text
-1.2345678900000000e+02 --> -2:03.456789 some text
1.2345600000000000e+04 --> 205:45.6 some text
-1.2345600000000000e+04 --> -205:45.6 some text
-0.0000000000000000e+00 --> -0:00. some text
0.0000000000000000e+00 --> 0:00. some text
5.9999999400000000e+01 --> 0:59.999999 some text
-5.9999999400000000e+01 --> -0:59.999999 some text
5.9999999600000002e+01 --> 1:00. some text
-5.9999999600000002e+01 --> -1:00. some text
1.1805916207174113e+21 --> 19676527011956854784:04. some text
-1.1805916207174113e+21 --> -19676527011956854784:04. some text
1.7976931348623157e+308 --> 2996155224770526471302168869341711813188863000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:08. some text
-1.7976931348623157e+308 --> -2996155224770526471302168869341711813188863000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:08. some text
inf --> inf some text
-inf --> -inf some text
nan --> nan some text
-nan --> -nan some text
答案 2 :(得分:-1)
这种方法使用堆栈而不是堆内存,因此它应该更快。
目标是快速代码,小占用空间和非常大的值无关紧要。 仅在非常罕见的圆角情况下,才需要更多的CPU周期。
它还可以与其他格式和其他printf()
中的值组合。
新:格式的另一种解决方案:h:mm:ss.nnnnnn
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <math.h>
#define MAX_BUF_SZ 32
#ifndef DBL_MAX
#define DBL_MAX 1.7976931348623157e+308
#endif
static char *minutes_str(char *buf, double time) {
const char *format = (time >= 0 ? "%d:%09.6f" : "-%d:%09.6f");
time = (fabs(time) > INT_MAX * 60.0 ? INT_MAX * 60.0 : fabs(time));
int len = snprintf(buf, MAX_BUF_SZ, format, (int)(time / 60), fmod(time, 60));
if (len - 9 >= 0 && buf[len - 9] > '5') // correct rare rounding issue
len = snprintf(buf, MAX_BUF_SZ, format, (int)(time / 60) + 1, .0);
while (buf[--len] == '0'); // search trailing zeros or ...
buf[len + (buf[len] != '.')] = '\0'; // dot and strip them
return buf;
}
/**
* Convenience macro. The return value should be used only directly in
* function arguments but never stand-alone.
*/
#define time2minutestr(time) minutes_str((char[MAX_BUF_SZ]){'\0'}, time)
static char *hours_string(char *buf, double time)
{
const char *format = (time >= 0 ? "%d:%02d:%09.6f" : "-%d:%02d:%09.6f");
if (time == (double)NAN)
printf("Invalid number\n");
time = (fabs(time) > INT_MAX * 60.0 * 60.0 ? INT_MAX * 60.0 * 60.0 : fabs(time));
int hours = time / 60 / 60, minutes = fmod(time / 60, 60);
int len = snprintf(buf, MAX_BUF_SZ, format, hours, minutes, fmod(time, 60));
if (len - 9 >= 0 && buf[len - 9] > '5') { // correct rare rounding issue
if (++minutes > 59) {
minutes = 0;
hours++;
}
len = snprintf(buf, MAX_BUF_SZ, format, hours, minutes, .0);
}
while (buf[--len] == '0'); // search trailing zeros or ...
buf[len + (buf[len] != '.')] = '\0'; // dot and strip them
return buf;
}
/**
* Convenience macro. The return value should be used only directly in
* function arguments but never stand-alone.
*/
#define time2hourstr(time) hours_string((char[MAX_BUF_SZ]){'\0'}, time)
int main(int argc, char** argv)
{
double a[] = {
0, -1, 1, 59, 60, 61,
121.1, 121.11, 121.111, 121.1111, 121.11111, 121.111111,
12345.6,
123.456789,
129.9999994,
129.9999995,
599.9999994,
599.9999995,
599.99999951,
599.9999999,
23.9999999999,
999.0000005, 1000.0000005, -999.0000005, -1000.0000005,
999.9999999, -999.9999999,
1e6, 1e12, 1e18,
4321.0, -0.0, 59.9999994, 59.9999996,
INT_MAX * 60.0, INT_MAX * 60.0 + 1234,
-(INT_MAX + 1.0) * 60.0, -(INT_MAX + 1.0) * 60.0 - 1234,
(double)ULLONG_MAX * 64.0, DBL_MAX, 1.0 / 0.0, (double)NAN,
};
size_t i;
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
printf("%32.16g", a[i]);
printf(" --> %s %s\n", time2minutestr(a[i]), "some text");
printf("%32.16g", -a[i]);
printf(" --> %s %s\n", time2minutestr(-a[i]), "some text");
}
printf(" H A P P Y !\n");
double b[] = {
0, -1, 1, 59, 60, 61,
12345.6,
123.456789,
3609.9999995,
3609.99999951,
359999.9999994,
359999.9999995,
359999.99999951,
719999.9999995, 7199.9999999999,
1e6, 1e12, 1e18,
INT_MAX * 60.0, INT_MAX * 60.0 * 60.0,
-(INT_MAX + 1.0) * 60.0, -(INT_MAX + 1.0) * 60.0 * 60.0,
(double)ULLONG_MAX * 64.0, DBL_MAX, 1.0 / 0.0, (double)NAN,
};
for (i = 0; i < sizeof(b) / sizeof(b[0]); i++) {
printf("%32.16g", b[i]);
printf(" --> %s %s\n", time2hourstr(b[i]), "some other text");
printf("%32.16g", -b[i]);
printf(" --> %s %s\n", time2hourstr(-b[i]), "some other text");
}
printf(" V E R Y H A P P Y !\n");
return (0);
}
输出:
0 --> 0:00 some text
-0 --> 0:00 some text
-1 --> -0:01 some text
1 --> 0:01 some text
1 --> 0:01 some text
-1 --> -0:01 some text
59 --> 0:59 some text
-59 --> -0:59 some text
60 --> 1:00 some text
-60 --> -1:00 some text
61 --> 1:01 some text
-61 --> -1:01 some text
121.1 --> 2:01.1 some text
-121.1 --> -2:01.1 some text
121.11 --> 2:01.11 some text
-121.11 --> -2:01.11 some text
121.111 --> 2:01.111 some text
-121.111 --> -2:01.111 some text
121.1111 --> 2:01.1111 some text
-121.1111 --> -2:01.1111 some text
121.11111 --> 2:01.11111 some text
-121.11111 --> -2:01.11111 some text
121.111111 --> 2:01.111111 some text
-121.111111 --> -2:01.111111 some text
12345.6 --> 205:45.6 some text
-12345.6 --> -205:45.6 some text
123.456789 --> 2:03.456789 some text
-123.456789 --> -2:03.456789 some text
129.9999994 --> 2:09.999999 some text
-129.9999994 --> -2:09.999999 some text
129.9999995 --> 2:10 some text
-129.9999995 --> -2:10 some text
599.9999994 --> 9:59.999999 some text
-599.9999994 --> -9:59.999999 some text
599.9999994999999 --> 9:59.999999 some text
-599.9999994999999 --> -9:59.999999 some text
599.99999951 --> 10:00 some text
-599.99999951 --> -10:00 some text
599.9999999 --> 10:00 some text
-599.9999999 --> -10:00 some text
23.9999999999 --> 0:24 some text
-23.9999999999 --> -0:24 some text
999.0000005000001 --> 16:39.000001 some text
-999.0000005000001 --> -16:39.000001 some text
1000.0000005 --> 16:40.000001 some text
-1000.0000005 --> -16:40.000001 some text
-999.0000005000001 --> -16:39.000001 some text
999.0000005000001 --> 16:39.000001 some text
-1000.0000005 --> -16:40.000001 some text
1000.0000005 --> 16:40.000001 some text
999.9999999 --> 16:40 some text
-999.9999999 --> -16:40 some text
-999.9999999 --> -16:40 some text
999.9999999 --> 16:40 some text
1000000 --> 16666:40 some text
-1000000 --> -16666:40 some text
1000000000000 --> 2147483647:00 some text
-1000000000000 --> -2147483647:00 some text
1e+18 --> 2147483647:00 some text
-1e+18 --> -2147483647:00 some text
4321 --> 72:01 some text
-4321 --> -72:01 some text
-0 --> 0:00 some text
0 --> 0:00 some text
59.9999994 --> 0:59.999999 some text
-59.9999994 --> -0:59.999999 some text
59.9999996 --> 1:00 some text
-59.9999996 --> -1:00 some text
128849018820 --> 2147483647:00 some text
-128849018820 --> -2147483647:00 some text
128849020054 --> 2147483647:00 some text
-128849020054 --> -2147483647:00 some text
-128849018880 --> -2147483647:00 some text
128849018880 --> 2147483647:00 some text
-128849020114 --> -2147483647:00 some text
128849020114 --> 2147483647:00 some text
1.180591620717411e+21 --> 2147483647:00 some text
-1.180591620717411e+21 --> -2147483647:00 some text
1.797693134862316e+308 --> 2147483647:00 some text
-1.797693134862316e+308 --> -2147483647:00 some text
inf --> 2147483647:00 some text
-inf --> -2147483647:00 some text
nan --> --2147483648: nan some text
-nan --> --2147483648: nan some text
H A P P Y !
0 --> 0:00:00 some other text
-0 --> 0:00:00 some other text
-1 --> -0:00:01 some other text
1 --> 0:00:01 some other text
1 --> 0:00:01 some other text
-1 --> -0:00:01 some other text
59 --> 0:00:59 some other text
-59 --> -0:00:59 some other text
60 --> 0:01:00 some other text
-60 --> -0:01:00 some other text
61 --> 0:01:01 some other text
-61 --> -0:01:01 some other text
12345.6 --> 3:25:45.6 some other text
-12345.6 --> -3:25:45.6 some other text
123.456789 --> 0:02:03.456789 some other text
-123.456789 --> -0:02:03.456789 some other text
3609.9999995 --> 1:00:09.999999 some other text
-3609.9999995 --> -1:00:09.999999 some other text
3609.99999951 --> 1:00:10 some other text
-3609.99999951 --> -1:00:10 some other text
359999.9999994 --> 99:59:59.999999 some other text
-359999.9999994 --> -99:59:59.999999 some other text
359999.9999995 --> 99:59:59.999999 some other text
-359999.9999995 --> -99:59:59.999999 some other text
359999.99999951 --> 100:00:00 some other text
-359999.99999951 --> -100:00:00 some other text
719999.9999995 --> 199:59:59.999999 some other text
-719999.9999995 --> -199:59:59.999999 some other text
7199.9999999999 --> 2:00:00 some other text
-7199.9999999999 --> -2:00:00 some other text
1000000 --> 277:46:40 some other text
-1000000 --> -277:46:40 some other text
1000000000000 --> 277777777:46:40 some other text
-1000000000000 --> -277777777:46:40 some other text
1e+18 --> 2147483647:00:00 some other text
-1e+18 --> -2147483647:00:00 some other text
128849018820 --> 35791394:07:00 some other text
-128849018820 --> -35791394:07:00 some other text
7730941129200 --> 2147483647:00:00 some other text
-7730941129200 --> -2147483647:00:00 some other text
-128849018880 --> -35791394:08:00 some other text
128849018880 --> 35791394:08:00 some other text
-7730941132800 --> -2147483647:00:00 some other text
7730941132800 --> 2147483647:00:00 some other text
1.180591620717411e+21 --> 2147483647:00:00 some other text
-1.180591620717411e+21 --> -2147483647:00:00 some other text
1.797693134862316e+308 --> 2147483647:00:00 some other text
-1.797693134862316e+308 --> -2147483647:00:00 some other text
inf --> 2147483647:00:00 some other text
-inf --> -2147483647:00:00 some other text
nan --> --2147483648:-2147483648: some other text
-nan --> --2147483648:-2147483648: some other text
V E R Y H A P P Y !