c - 如何在可移植 C 中将很长的字符串转换为 double

标签 c atof strtod

我想在 C 中以可移植的方式将很长的数字字符串转换为 double 。在我的例子中,可移植意味着它可以在 Linux 和 Windows 中工作。我的最终目标是能够将一串数字打包成一个 8 字节的 double 和 fwrite/fread 到/从一个二进制文件。该数字始终是无符号的。

我正在使用此字符串来打包 4 位数字年份、2 位数字月份、2 位数字日期、4 位数字 HH:MM、1 位数字变量和 10 位数字值。因此,试图将 23 个字节打包成 8 个字节。

我已经尝试了所有标准的东西:

char myNumAsString[] = "1234567890123456789";

char *ptr;
char dNumString[64];
double dNum;


dNum = atol(myNumAsString);
sprintf(dNumString, "%lf", dNum);

dNum = atof(myNumAsString);
sprintf(dNumString, "%lf", dNum);

dNum = strtod(myNumAsString, &ptr);
sprintf(dNumString, "%lf", dNum);

sscanf(myNumAsString, "%lf", &dNum);
sprintf(dNumString, "%lf", dNum);

这些都不起作用;他们都把最后几个数字四舍五入。有什么便携的方法可以做到这一点?

最佳答案

利用字符串的一部分是时间戳而不是任何数字集。

有60分钟,24小时,365.25天/年,y年,一个数字和10个数字,有60*24*365.25*y*10*pow(10, 10) 组合或关于 5.3e16 * y

一个 8 字节、64 位的数字有 1.8e19 组合。因此,如果年份的范围为 350 年或更短(例如 1970 年到 2320 年),则一切都适合。

假设是 unix 时间戳,并且 OP 可以将时间字符串转换为 time_t(查看 mktime())....

time_t epoch = 0;  // Jan 1, 1970, Adjust as needed.

uint64_t pack(time_t t, int digit1, unsigned long long digit10) {
  uint64_t pack = digit1 * 10000000000 + digit10;
  time_t tminutes = (t - epoch)/60;

  pack += tminutes*100000000000;
  return pack;
}

反向打开包装。


或更完整的可移植包装(代码未经测试)

#include <time.h>
// pack 19 digit string
// "YYYYMMDDHHmm11234567890"
uint64_t pack(const char *s) {
  struct tm tm0 = {0};
  tm0.tm_year = 1970 - 1900;
  tm0.tm_mon = 1-1;
  tm0.tm_mday = 1;
  tm0.tm_isdst = -1;
  time_t t0 = mktime(&tm0);  // t0 will be 0 on a Unix system
  struct tm tm = {0};
  char sentinal;
  int digit1;
  unsigned long long digit10;
  if (strlen(s) != 4+2+2+2+2+1+10) return -1;
  if (7 != sscanf(s, "%4d%2d%2d%2d%2d%1d%10llu%c", &tm.tm_year,
          &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min,
          &digit1, &digit10, &sentinal)) return -1;
  tm.tm_year -= 1900;
  tm.tm_mon--;
  tm.tm_isdst = -1;
  time_t t = mktime(&tm);

  double diff_sec = difftime(t, t0);
  unsigned long long diff_min= diff_sec/60;
  return diff_min * 100000000000 + digit1*10000000000ull + digit10;
}

关于c - 如何在可移植 C 中将很长的字符串转换为 double ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32159628/

相关文章:

c++ - 如何在 OS X Yosemite 上安装 FreeGlut(3.0.0 或 2.8.0)

c++ - 从 bmp(或其他图像类型)中提取第 "n"个图像

c - 如何在 C 中重新定义字符指针中的内容

C++ atof.如何检查输入错误?

C - 从字符串中提取所有数字

c - 从 csv 读取,strtod 无法读取带有数字的字符串

c++ - 困惑如何在 C++ 中使用 strtod() 从字符串转换为 double

c - 调用自制 C 函数时出现段错误

floating-point - atof 的奇怪行为

c++ - atof 和非空终止字符数组