Независимые от реализации преобразования с плавающей запятой / целочисленные - PullRequest
3 голосов
/ 07 ноября 2019

Предположим, I - это некоторый целочисленный тип, а F - некоторый (действительный) тип с плавающей запятой.

Я хочу написать две функции. Первая функция должна принимать значение i типа I и возвращать логическое значение, указывающее, попадает ли i, преобразованный в F, в представимый диапазон, т. Е. Будет ли (F)i иметь определенное поведение.

Вторая функция должна принимать значение f типа F и возвращать логическое значение, указывающее, попадает ли f, преобразованный в I, в представимый диапазон, т. Е. Будет ли (I)f иметь определенное поведение.

Можно ли написать такую ​​функцию, которая в каждой реализации, соответствующей стандарту, будет корректной и не будет демонстрировать неопределенного поведения для любого ввода? В частности, я не хочу предполагать, что типы с плавающей запятой являются типами IEEE 754.

Я спрашиваю как о C, так и C ++ и их соответствующих стандартных версиях отдельно, на случай, если это изменит ответ.

По сути, целью этого вопроса является выяснить, возможны ли (разумные) преобразования с плавающей запятой / интегральной, не полагаясь на IEEE 754 или другие стандарты или аппаратные детали вообще. Я спрашиваю из любопытства.

Сравнение с, например, INT_MAX или FLT_MAX не представляется возможным, поскольку неясно, в каком типе проводить сравнение, не зная, какой из типов ширедиапазон.

1 Ответ

1 голос
/ 07 ноября 2019

некоторое число с плавающей запятой до некоторое значение типа int довольно просто, можно предположить, что FLT_RADIX != 10 (2 N число с плавающей запятой) и диапазон FP превышает целое числодиапазон.

Форма точные пределы FP
Проверка, если FP имеет дробную часть, которая составляет 0 **. (также обрабатывает NaN, inf)
Проверить, не слишком ли положительный.
Проверить, не слишком ли отрицательный.
Проверить, преобразовано ли в целочисленное значение.

Псевдокод

// For now, assume 2's complement.
// With some extra macro magic, could handle all integer encodings. 

// Use integer limits whose magnitudes are at or 1 away from a power-of-2  
//   and form FP power-of-2 limits 
// The following will certainly not incur any rounding
#define FLT_INT_MAXP1 ((INT_MAX/2 + 1)*2.0f)
#define FLT_INT_MIN (INT_MIN*1.0f)

status float_to_int_test(float f) {
  float ipart;
  if (modff(f, &ipart) != 0.0) {
    return not_a_whole_number;
  }
  if (f >= FLT_INT_MAXP1) return too_big;
  if (f < FLT_INT_MIN) return too_negative;
  if (f != (volatile float) f)) return rounding_occurred;
  return success;
}

Вооружен вышеуказанным тестом float_to_int ....

status int_to_float_test(int i) { 
  volatile float f = (float) i;
  if (float_to_int_test(f) != success) return fail
  volatile int j = (int) f;
  if (i != j) return fail;
  return success;
}

Упрощения возможны, но кое-что можно получить OPначало.

Крайние случаи, для которых требуется дополнительный код, включают int128_t или более широкий диапазон, превышающий float и FLT_RADIX == 10.


** Хммм- Похоже, ОП не заботится о дробной части. В этом случае преобразование из double в int выглядит как хороший дубликат для половины проблемы.

...