Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проверка float на "численность"
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
MrYuran
Сейчас встретил в программе кусок
Код
sprintf(str, "%f", fCNa);
if(isalpha(str[1]))fCNa = 0;

Я так подозреваю, что это проверка fCNa на допустимость
(или как там по-русски сказать)

Если это так, то решение, по-моему, слишком избыточное, учитывая что *printf() нигде больше не используется

Какие могут быть другие способы, менее затратные?
Палыч
Цитата(MrYuran @ Feb 3 2009, 13:39) *
Какие могут быть другие способы, менее затратные?
Если это - IEEE754, то "нечисла" (положительная и отрицательная бесконечность, нечисло, неопределённость) имеют в порядке (двоичное представление) все единицы. "Нормальные" числа в порядке содержат по крайней мере один нолик.
shreck
Цитата(MrYuran @ Feb 3 2009, 17:39) *
Какие могут быть другие способы, менее затратные?

Я пользуюсь таким кодом:
CODE
//******************************************************************************
// MISC_CPP
// DESCRIPTION:
// Различного рода вспомагательные функции.
//
//
//******************************************************************************

//------------------------------------------------------------------------------
// T Y P E S and D E F I N I T I O N S
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Константa NaN.
const float NaN = 0.0/0.0;

//==============================================================================
// I M P L E M E N T A T I O N
//==============================================================================

//------------------------------------------------------------------------------
// Проверка значения float на число.
bool is_nan(float val)
{
uint32 *pval = reinterpret_cast<uint32*>(&val);
bool result = ((*pval & 0x7F800000) == 0x7F800000) &&
((*pval & 0x007FFFFF) != 0x00000000);
return result;
}

//------------------------------------------------------------------------------
// Проверка значения float на бесконечность.
bool is_inf(float val)
{
uint32 *pval = reinterpret_cast<uint32*>(&val);
bool result = ((*pval & 0x7F800000) == 0x7F800000) &&
((*pval & 0x007FFFFF) == 0x00000000);
return result;
}

//------------------------------------------------------------------------------
// Проверка значения float на корректность. Не Nan и не Inf.
bool is_correct_float(float val)
{
return !(is_nan(val)||is_inf(val));
}
MrYuran
Цитата(shreck @ Feb 3 2009, 14:36) *
Я пользуюсь таким кодом:
...
uint32 *pval = reinterpret_cast<uint32*>(&val);
...

Спасибо, а вот это
reinterpret_cast<uint32*> - на каком языке написано?
я так подозреваю, на си это что-то типа (uint32*)?
vik0
Цитата(MrYuran @ Feb 3 2009, 13:53) *
reinterpret_cast<uint32*> - на каком языке написано?
я так подозреваю, на си это что-то типа (uint32*)?

C++
Правильно подозреваете.

Цитата(shreck @ Feb 3 2009, 13:36) *
...

Все уже придумано до нас smile.gif
Код
#include <limits>
// Проверка значения float на корректность. Не Nan и не Inf.
bool is_correct_float(float val)
{
    return val != std::numeric_limits<float>::signaling_NaN() &&
      abs(val) != std::numeric_limits<float>::infinity();
}
Сергей Борщ
Цитата(vik0 @ Feb 3 2009, 14:14) *
Все уже придумано до нас smile.gif
Действительно, придумано.
Код
#include <math.h>
// Проверка значения float на корректность.
bool is_correct_float(float val)
{
    return !isnan(val);
}
vik0
Цитата(Сергей Борщ @ Feb 3 2009, 14:50) *

А как быть с +/-INF ?
MrYuran
В общем, всем спасибо, сделал misc.c как у shreсk'a, только на си.
Результат - минус 4 кило из сегмента code и увеличение запаса оперативки
Так вот живёшь-живешь, и вдруг - бац, оказывается, float принято на пределы проверять...
Сергей Борщ
Цитата(vik0 @ Feb 3 2009, 15:04) *
А как быть с +/-INF ?
Откровенно говоря не силен в плавающей точке, но логика подсказывает, что inf - это тоже not a number, и, значит, должен отсекаться по isnan(). Лезть в стандарт?
Да, полез: это разные классы чисел. Надо использовать isfinite():
Цитата
The isfinite macro determines whether its argument has a finite value (zero, subnormal, or normal, and not infinite or NaN).



Цитата(MrYuran @ Feb 3 2009, 15:30) *
В общем, всем спасибо, сделал misc.c как у shreсk'a, только на си.
Ошибочное решение. Представление плавающей точки - компиляторо- и процессорозависимо. Вы закладываететсь на конкретную реализацию, теряя портабельность. Разработчики компиляторов предоставляют стандартные макросы для этих операций - isnan() isinf() и кучу других. Если вас не устраивает их встраивание - сделайте обертки, но не закладывайтесь на конкретное представление чисел компилятором.
aaarrr
По-моему, правильно будет использовать isfinite():
Цитата
The isfinite macro determines whether its argument has a finite value (zero,
subnormal, or normal, and not infinite or NaN).
Сергей Борщ
Цитата(aaarrr @ Feb 3 2009, 15:49) *
По-моему, правильно будет использовать isfinite():
Говорят, у дураков мысли сходятся... Но у умных чаще! smile.gif
vik0
Цитата(Сергей Борщ @ Feb 3 2009, 15:46) *
inf - это тоже not a number, и, значит, должен отсекаться по isnan().

Беглая проверка показала что MSVC++2008 так не считает. unsure.gif
Цитата
Лезть в стандарт?

Гляньте, если не затруднит. Хочется прояснить для себя этот вопрос.
shreck
Цитата(Сергей Борщ @ Feb 3 2009, 20:46) *
Ошибочное решение. Представление плавающей точки - компиляторо- и процессорозависимо. Вы закладываететсь на конкретную реализацию, теряя портабельность. Разработчики компиляторов предоставляют стандартные макросы для этих операций - isnan() isinf() и кучу других. Если вас не устраивает их встраивание - сделайте обертки, но не закладывайтесь на конкретное представление чисел компилятором.

Полностью поддерживаю. Но...
1. Не у всех компиляторов стандартная библиотека содержит указанные функции, например, в IARMSP342 я их не нашел.
2. Если документация к компилятору утверждает, что он поддерживает для float стандарт IEEE 754, то, рискну предположить, что приведенный мной код не компиляторо- и не процессорозависимый.
3. Человеку нужно решение на С.
Палыч
Цитата(shreck @ Feb 4 2009, 06:40) *
... поддерживает для float стандарт IEEE 754, то, рискну предположить, что приведенный мной код не компиляторо- и не процессорозависимый.
В Вашем коде есть одно "тёмное" место - приведение указателя на float к указателю на uint32. Правильность работы Вашего кода будет определятся - как транслятор располагает в памяти байты целых и вещественных чисел. Если - в используемом трансляторе нет стандартной функции определения "нечисла", то, имхо, с этим "тёмным" местом кода можно смириться.
Сергей Борщ
Цитата(shreck @ Feb 4 2009, 05:40) *
1. Не у всех компиляторов стандартная библиотека содержит указанные функции, например, в IARMSP342 я их не нашел.
Тут возразить нечего... Разве что можно предложить дать этим функциям стандартные названия, чтобы при компиляции компилятором, который имеет такие функции, получить ошибку и заменить их на библиотечные.
Цитата(shreck @ Feb 4 2009, 05:40) *
2. Если документация к компилятору утверждает, что он поддерживает для float стандарт IEEE 754, то, рискну предположить, что приведенный мной код не компиляторо- и не процессорозависимый.
А как же большие и маленькие индейцы? Затык именно в попытке обращаться к участку памяти как к длинному целому. К тому же, в зависимости от реализации компилятора, и float и double могут иметь непредсказуемое число бит.
Цитата(shreck @ Feb 4 2009, 05:40) *
3. Человеку нужно решение на С.
Вызов описанного в стандарте языка макроса стандартной библиотеки - самое что ни на есть "решение на С".
MrYuran
Извиняюсь за занудство...
CODE

/* - MATH.H -

The ANSI-defined (+ a few additional) mathematical functions.

$Revision: 1.4 $

Copyright 1986 - 1999 IAR Systems. All rights reserved.
*/

#ifndef _MATH_INCLUDED
#define _MATH_INCLUDED

#ifndef _SYSTEM_BUILD
#pragma system_include
#endif

#include "sysmac.h"

#ifndef HUGE_VAL
#if __FLOAT_SIZE__ == __DOUBLE_SIZE__
#define HUGE_VAL 3.402823466e+38
#else
#define HUGE_VAL 1.7976931348623158e+308
#endif
#endif

/* What is returned if a domain error occurred */
#define __EDOM_VALUE HUGE_VAL

/* PI, PI/2, PI/4, 1/PI, 2/PI */
#define __PI 3.141592653589793238462643
#define __PIO2 1.570796326794896619231
#define __PIO4 .785398163397448309615
#define __INVPI 0.31830988618379067154
#define __TWOOPI 0.63661977236758134308

/* SQRT(2), SQRT(2) + 1, SQRT(2) - 1,SQRT(2) / 2 */
#define __SQRT2 1.4142135623730950488016887
#define __SQ2P1 2.414213562373095048802
#define __SQ2M1 .414213562373095048802
#define __SQRTO2 0.707106781186547524

/* LN(10), TWO-LOG(e), LN(2) e */
#define __LN10 2.302585092994045684
#define __LOG2E 1.4426950408889634073599247
#define __LOG2 0.693147180559945309417232
#define __E 2.718281828459045235360287


#if __IAR_SYSTEMS_ICC__ < 2
#if __TID__ & 0x8000
#pragma function=intrinsic(0)
#endif
#endif

#ifndef MEMORY_ATTRIBUTE
#define MEMORY_ATTRIBUTE
#endif

__INTRINSIC MEMORY_ATTRIBUTE double atan(double);

__INTRINSIC MEMORY_ATTRIBUTE double atan2(double, double);

__INTRINSIC MEMORY_ATTRIBUTE double cos(double);

__INTRINSIC MEMORY_ATTRIBUTE double cosh(double);

__INTRINSIC MEMORY_ATTRIBUTE double fabs(double);

__INTRINSIC MEMORY_ATTRIBUTE double fmod(double, double);

__INTRINSIC MEMORY_ATTRIBUTE double exp(double);

__INTRINSIC MEMORY_ATTRIBUTE double ldexp(double, int);

__INTRINSIC MEMORY_ATTRIBUTE double log(double);

__INTRINSIC MEMORY_ATTRIBUTE double log10(double);

__INTRINSIC MEMORY_ATTRIBUTE double modf(double, double *);

__INTRINSIC MEMORY_ATTRIBUTE double pow(double , double);

__INTRINSIC MEMORY_ATTRIBUTE double sin(double);

__INTRINSIC MEMORY_ATTRIBUTE double sinh(double);

__INTRINSIC MEMORY_ATTRIBUTE double sqrt(double);

__INTRINSIC MEMORY_ATTRIBUTE double tan(double);

__INTRINSIC MEMORY_ATTRIBUTE double tanh(double);

__INTRINSIC MEMORY_ATTRIBUTE double floor(double);

__INTRINSIC MEMORY_ATTRIBUTE double ceil(double);

__INTRINSIC MEMORY_ATTRIBUTE double frexp(double, int *);

__INTRINSIC MEMORY_ATTRIBUTE double acos(double);

__INTRINSIC MEMORY_ATTRIBUTE double asin(double);

#if __IAR_SYSTEMS_ICC__ < 2
#if __TID__ & 0x8000
#pragma function=default
#endif
#endif

#endif /* _MATH_INCLUDED */


Вот так... это ИАР для MSP
чё-то не находит он в math.h isnan(), isfinite() etc...
Может, где-то в другом месте прописано, искать лень...
В общем, всем спасибо и респект, портирование в ближайшие годы не предполагается, MSP rulez (особенно для портативных приложений)
Пока оставляю как есть.
Тем более что в тексте и так полно ручных крякозяблей, типа юниона float с char'ами, с последующей мануальной терапией...
А поскольку проект в целом рабочий и серия насчитывает несколько сотен экз. за 2 года, логично "не лечить то, что работает", просто где явно можно что-то улучшить, слегка подпиливаю.
Сергей Борщ
Цитата(MrYuran @ Feb 4 2009, 09:12) *
Вот так... это ИАР для MSP
чё-то не находит он в math.h isnan(), isfinite() etc...
У меня аналогичный файл в CLIB от версии 3.21А. Там и stdint.h нет и много еще чего полезного. А в math.h от DLIB - все есть. Так что выберите библиотеку DLIB в настройках проекта - и будет все хорошо.
rezident
Цитата(Сергей Борщ @ Feb 4 2009, 12:34) *
А в math.h от DLIB - все есть. Так что выберите библиотеку DLIB в настройках проекта - и будет все хорошо.
Угу. Либо DLIB использовать нужно, либо свою функцию написать.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.