On-line: гостей 1. Всего: 1 [подробнее..]
АвторСообщение





Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 26.04.06 01:41. Заголовок: Количество десятичных знаков в Clipper


Кто знает, как определить количество назначенных числу десятичных знаков, например, 10.0 или 10.000? Или чуть проще: как отличить изначальное целое число от дробного результата каких-либо вычислений? INT() помогает только если дробная часть ненулевая...

Спасибо: 0 
Профиль
Ответов - 32 , стр: 1 2 All [только новые]


постоянный участник


Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 04.05.06 11:37. Заголовок: Re:


В связи с тестированием функции, которую я (и в виде C-функции также saulius)предложил по этой теме, открылись важные обстоятельства, которые изначально трудно было предвидеть.
Во-первых, функция работает правильно. Для данных типа Long предоставляется два слова, следовательно максимально целое положительное число, которое может храниться в переменной типа Long, равняется 7FFFFFFFh (в шестнадцатиричном виде).
Однако надеятся на то, что переменная сохранит тип Long очень трудно. Clipper при первой возможности старается перевести Long в Double. Например, если имеется переменная nNumber типа Long равная 4, то при операции
nNumber = nNumber / 2
nNumber получит тип Double, хотя 4 делится нацело на 2.
Во-вторых, если в исходном коде программы имеется предложение, например,
nNumber := 10
то Clipper при компилировании константу 10 непосредственно вставляет в свой результирующий байт-код. Для целых констант Clipper в своем байт-коде отводит одно слово, следовательно максимальное значение целой константы, хранимое в байт-коде, равняется 7FFFh. Соответственно для отрицательных целых чисел максимальное (по абсолютной величине) значение будет равно 8001h. В десятичном представлении это соответственно значения 32767 и -32767. Если же значение константы в исходном коде больше данных граничных значений, то Clipper при компиляции сам переводит эти константы в тип Double.
Я не проверял, что происходит, когда в переменную вводится число с помощью команды GET. Возможно, что оно сохраняет целый тип, если значение вводилось по формату, не содержащем десятичную точку.
Итак вывод. Переменная типа Long может хранить целые значения от 80000001h (отрицательное число) до 7FFFFFFFh (положительное число). Все константы в диапазоне от - 32767 до 32767 Clipper при компиляции непосредственно помещвет в свой байт-код как целые числа. Если константы выходят из этого диапазона в исходном коде на Clipper, то Clipper при компиляции преобразует их в в константы с плавающей запятой.



Спасибо: 0 
Профиль
постоянный участник


Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 04.05.06 11:44. Заголовок: Re:


Вот исходный код примера, который я запускал, и его результат

PROCEDURE MAIN()
LOCAL nNegLong, nLong, nDouble
LOCAL nCount

nLong := 32767
? "nLong =", nLong, "is Long ==", IsLong( nLong ),;
"nLong =", nLong, "is Double ==", IsDouble( nLong )

nCount := 0
DO WHILE ( IsLong( nLong ) .AND. nCount++ < 32768 )
nLong++
ENDDO

? "nLong =", nLong, "is Long ==", IsLong( nLong ),;
"nLong =", nLong, "is Double ==", IsDouble( nLong )

nLong := 32768
? "nLong =", nLong, "is Long ==", IsLong( nLong ),;
"nLong =", nLong, "is Double ==", IsDouble( nLong )

nNegLong := -32767
? "nNegLong =", nNegLong, "is Long ==", IsLong( nNegLong ),;
"nNegLong =", nNegLong, "is Double ==", IsDouble( nNegLong )

nNegLong := -32768
? "nNegLong =", nNegLong, "is Long ==", IsLong( nNegLong ),;
"nNegLong =", nNegLong, "is Double ==", IsDouble( nNegLong )

nDouble := 1.0
? "nDouble =", nDouble, "is Double ==", IsDouble( nDouble ),;
"nDouble =", nDouble, "is Long ==", IsLong( nDouble )

RETURN
=============
Результат

nLong = 32767 is Long == .T. nLong = 32767 is Double == .F.
nLong = 65535 is Long == .T. nLong = 65535 is Double == .F.
nLong = 32768 is Long == .F. nLong = 32768 is Double == .T.
nNegLong = -32767 is Long == .T. nNegLong = -32767 is Double == .F.
nNegLong = -32768 is Long == .F. nNegLong = -32768 is Double == .T.
nDouble = 1.0 is Double == .T. nDouble = 1.0 is Long == .F.

Спасибо: 0 
Профиль



Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 04.05.06 13:27. Заголовок: Re:


А как будет с
nX := 3000 / 2
nX := 3000 / 3
nX := 3 % 1
...
вывод ?

Спасибо: 0 
Профиль
постоянный участник


Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 04.05.06 13:42. Заголовок: Re:


Я смогу проверить только сегодня вечером, так как нет Clipper под рукой. Но по своей памяти я могу сказать, что Clipper при компиляции заменяет некоторые константные выражения результирующим значением.

Например, если в программе есть такой код

#define BOX_TOP 10

LOCAL nTop

то при компиляции предложения
nTop := BOX_TOP + 5
Clipper вычислит значение BOX_TOP + 5 равное 15 и именно константу 15 занесет в байт-код.
Что касается операций деления, то тут, как я уже сказал, надо проверить, как их вычисляет Clipper при компиляции.

Спасибо: 0 
Профиль





Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 05.05.06 07:53. Заголовок: Re:


saulius пишет:

 цитата:
ывод ?


Вывод такой, что функциями IsDouble() и IsLong() нужный результат - отличие любого целого числа от любого дробного (которое может быть и с нулевой дробной частью) - не достигается.
Более того, я обнаружил, что взятое из поля Numeric размерностью 8 число 9600 воспринимается как Double, что уже неприемлемо.

Спасибо: 0 
Профиль
постоянный участник


Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 05.05.06 11:30. Заголовок: Re:


saulius wrote:

 цитата:
А как будет с
nX := 3000 / 2
nX := 3000 / 3
nX := 3 % 1
...
вывод ?


Я вчера проверил: если при делении целых констант получается целое число, то Clipper в свой байт-код вставляет результат деления. То есть для указанных вами выражений Clipper при компиляции будет использовать на самом деле следующие выражения
nX := 1500
nX := 1000
nX := 0
или, например, для nX := 3 % 2
nX := 1
Во всех случаях nX будет целом числом, то есть тип для nX будет Long.

Лукашевский wrote:

 цитата:
Вывод такой, что функциями IsDouble() и IsLong() нужный результат - отличие любого целого числа от любого дробного (которое может быть и с нулевой дробной частью) - не достигается.



Вывод неправильный. Функции IsLong() и IsDouble() как раз позваляют отличать числа, хранимые Clipper как целые, от чисел, хранимые Clipper в виде чисел с плавающей запятьй, то есть как Double.
Другое дело, что существуют некоторые ограничение. Самое главное, что при компиляции исходного кода Clipper все целые константы, не попадающие в диапазон от -32767 до 32767 переводит на этапе компиляции в числа с плавающей запятой. Отсюда разночтение. Если программист, имея код nX := 32768, думает, что nX будет целого типа, то на самом деле Clipper переведет 32768 в число с плавающей запятой, и nX получит тип Double.
Второй момент состоит в том. что при различных арифметических операциях Clipper сам прозрачно для программиста часто переводит тип Long в тип Double. Уследить это очень трудно. Тем не менее с помощью функций IsLong() и IsDouble() вы в любой момент можете сами проверить, какой тип имеет переменная.
Что касается первоначальной проблемы, то я думаю, нужно искать другое проектное решение.

Спасибо: 0 
Профиль





Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 06.05.06 02:55. Заголовок: Re:


Григорьев Владимир пишет:

 цитата:
Другое дело, что существуют некоторые ограничение.


Тогда уж некоторые ограничениЯ. И главным из которых лично для меня является невозможность определения любого целого числа как целого (даже если оно меньше 32768), если это число извлечено из целочисленного поля типа Numeric DBF-файла, при этом размерность поля, как выяснилось, не играет никакой роли.
ЛЮБОЕ ЧИСЛО, ВЗЯТОЕ ИЗ ПОЛЯ, ИМЕЕТ ТИП Double АВТОМАТИЧЕСКИ!
В результате смысл использования функций IsLong() и IsDouble() стремится к нулю, ибо отслеживать, как образовывались значения оцениваемых переменных - присвоены они или взяты из поля - практически нереально.

Спасибо: 0 
Профиль
постоянный участник


Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 06.05.06 11:37. Заголовок: Re:


Как я уже сказал, значит надо по-другому подходить к вопросу проектирования требуемой функциональности. Если поля базы данных Clipper в любом случае считывает в память в виде значений с плавающей запятой, то тогда ваша постановка вопроса становится непонятной и требует уточнения в свете данных обстоятельств. Что вы понимаете под целыми числами и числами с плавающей запятой, у которых дробная часть равна нулю? Откуда появляются эти числа (при какой операции или действии пользователя) или это различие? И т.д. То есть нужно понять, что является источником проблемы и какой проблемы.

Спасибо: 0 
Профиль





Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 07.05.06 08:01. Заголовок: Re:


Григорьев Владимир пишет:

 цитата:
Что вы понимаете под целыми числами и числами с плавающей запятой, у которых дробная часть равна нулю? Откуда появляются эти числа


x := 10.010 * 100
?x 1001.000
Вы хотели пример, откуда появляются эти числа. Да и просто присвоение даёт тот же результат:
x:=1001.000
?x 1001.000
А вот в целом числе, присвоенном или взятом из поля, дробной части нет (даже если это число больше 32767):
x:=sklad->cena_otpu
?x 60000
Проблема как раз и состоит в том, что эти ситуации надо как-то различать. Для чего это нужно, я уже отвечал в одном из первых ответов в этой теме: в функцию приходит параметр, и если он - целое число, то перед дальнейшими операциями его нужно разделить на 1000, а если дробное (даже с нулевой дробной частью) - то делить не нужно категорически.


Спасибо: 0 
Профиль



Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 01.06.06 18:22. Заголовок: Может быть, это решение поможет


// Определяет размер числовой переменной: { всего позиций, дес.позиций }
Function SizeVar(nValue,nMode)
//
LOCAL nAt, nSizePos, nSizeDecPos, xRet

DEFAULT nMode TO 0

nValue := Str(nValue)
nSizePos := Len(nValue)
nSizeDecPos := IF( (nAt := At('.',nValue)) > 0, nSizePos-nAt, 0 )

DO CASE
CASE nMode == 0
xRet := { nSizePos, nSizeDecPos }
CASE nMode == 1
xRet := nSizePos
CASE nMode == 2
xRet := nSizeDecPos
CASE nMode == 3
xRet := Len(AllTrim(nValue))
ENDCASE

RETURN xRet



Спасибо: 0 





Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 08.06.06 10:15. Заголовок: Re:


Хотелось бы узнать,
подходит ли мой метод для определения
назначенных числу десятичных знаков или эта проблема нерешаема?

Спасибо: 0 
Профиль





Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 11.06.06 01:20. Заголовок: Re:


ort пишет:

 цитата:
Хотелось бы узнать,
подходит ли мой метод для определения
назначенных числу десятичных знаков


Вполне возможно... В самом начале моей бытвы с этой проблемой STR() у меня почему-то выдавал два знака после десятичной точки ВСЕГДА, даже на целое число. Сейчас проверил - всё нормально, для целого результат STR() без точки. Просто фантастика какая-то. Конечно, тогда проверкой на содержание "." в результате STR() вопрос решается!

Спасибо: 0 
Профиль
Ответов - 32 , стр: 1 2 All [только новые]
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 171
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет