Автор | Сообщение |
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 26.04.06 01:41. Заголовок: Количество десятичных знаков в Clipper
Кто знает, как определить количество назначенных числу десятичных знаков, например, 10.0 или 10.000? Или чуть проще: как отличить изначальное целое число от дробного результата каких-либо вычислений? INT() помогает только если дробная часть ненулевая...
|
|
|
Ответов - 32
, стр:
1
2
All
[только новые]
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 26.04.06 08:19. Заголовок: Re:
x:=10.00000001 y:=int(x) ? x==y
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 26.04.06 11:25. Заголовок: Re:
Надо узнать, какой тип данных возвращает Clipper. Для чисел у Clipper имеется два внутренних формата представления: Long (длинное целое) и Double (десятичное двойной точности)ю Если результат возвращается в виде Long, то очевидно никаких десятичных знаков нет. Если же в виде Double, то тут трудно определить. Double у Clipper хранится в формате Microsoft. Вот структура внутреннего представления Double (ассемблер TASM) STRUC DoubleHandleStr Type dw ? Length dw ? Decimals dw ? DoubleValue dq ? ; or dw 4 DUP( ? ) ENDS DoubleHandleStr Я не знаю, на сколько будет корректно проверять поле Decimals на равенство нулю. Но, я уже не помню, где-то внутри Clipper я встречал функцию, которая четко заносит в Decimals число десятичных знаков для данного внутреннего представления Double.
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 27.04.06 00:38. Заголовок: Re:
Именно "как отличить изначальное целое число от дробного результата каких-либо вычислений" я делаю так: проверяю CEILING() равно FLOOR()? Это из CLIPPER TOOLS II Одна функция округляет до ближайшего большего целого, другая - до ближайшего меньшего целого. Если они равны, то значит и аргумент целый.
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 27.04.06 01:28. Заголовок: Re: MikeP
CEILING() и FLOOR() я, конечно, попробую, но подозреваю, что разницу между 10 и 10.000 они мне не покажут... В том-то и проблема, что в дробной части могут быть сплошные нули, а определить, что это число не целое, а "как бы дробное", необходимо.
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 27.04.06 01:34. Заголовок: Re:
Dima пишет: цитата: | x:=10.00000001 y:=int(x) ? x==y |
| Дима, ты, наверное, не понял сути проблемы. А она в том, что в функцию, которая может быть вызвана из десятка мест в программе, приходит параметр, и если он целое число, то его нужно перед дальнейшими действиями в этой функции разделить на 1000, а если дробное, то оставить как есть. Проблема в том, что дробное число может быть и 10.000, т.е. в десятичных знаках могут быть одни нули, НО: число от этого не перестаёт быть дробным, и на 1000 его делить, соответственно, категорически не нужно...
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 27.04.06 01:39. Заголовок: Re:
Григорьев Владимир пишет: цитата: | Но, я уже не помню, где-то внутри Clipper я встречал функцию, которая четко заносит в Decimals число десятичных знаков для данного внутреннего представления Double. |
| Осталось только понять, как называется эта функция, а также как из Clipper получить доступ к значению Decimals
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 27.04.06 07:38. Заголовок: Re:
Еще один эксперимент: ? str(1/2) ? str(2/1) ? str(2.3/2.3) ? str(2/2) Результаты: 0.50 2 1.00 1 Возможно str() даст ответ на вопрос, како же в итоге внутренний рузультат получился?
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 27.04.06 11:41. Заголовок: Re:
Лукашевский цитата: | Осталось только понять, как называется эта функция, а также как из Clipper получить доступ к значению Decimals |
| Написать самому функцию типа IsLong( nNumParm ). Что-то вродк такого ( Borland TASM 4.01; не проверялась ) TITLE THE AUXILIARY CLIPPER 5.XX FUNCTION ISLONG IDEAL MODEL LARGE ISLONG_TEXT, CPP %NOINC INCLUDE "CTYPE.INC" ; в этот файл внести определение AnyHandleStr GLOBAL __retl: PROC GLOBAL __param: PROC GLOBAL IsLong: PROC False = 0000h True = 0001h Long = 0002h AnyType = 0FFFFh CODESEG ISLONG_TEXT ; Function format : IsLong( <nNumParm> ) --> lIsLong PROC IsLong mov ax,AnyType push ax mov ax,1 push ax call __param add sp,4 or ax,ax jz @@10 mov bx,ax test [(AnyHandleStr bx).Type],Long jz @@10 mov ax,True @@10: call __retl,ax ret ENDP IsLong END
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 27.04.06 11:48. Заголовок: Re:
Извините, в моем коде ошибочка закралась! PROC IsLong mov ax,AnyType push ax mov ax,1 push ax call __param add sp,4 or ax,ax jz @@10 mov bx,ax test [(AnyHandleStr bx).Type],Long jz @@10 mov ax,True jmp short @@20 @@10: mov ax,False @@20: call __retl,ax ret ENDP IsLong
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 27.04.06 11:57. Заголовок: Re:
if At('.', Str(NUM))> 0 //REAL else //INTEGER endif
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 28.04.06 06:14. Заголовок: Re:
MikeP пишет: цитата: | Возможно str() даст ответ на вопрос, како же в итоге внутренний рузультат получился? |
| Не знаю, не знаю... У меня STR(целое число) выдаёт результат с двумя нулями после точки...
|
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 28.04.06 06:17. Заголовок: Re:
Григорьев Владимир пишет: цитата: | Написать самому функцию типа IsLong( nNumParm ). |
| К сожалению, ни в асссемблере, ни в C программить не умею
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 28.04.06 10:24. Заголовок: Re:
Лукашевский цитата: | К сожалению, ни в асссемблере, ни в C программить не умею |
| Сообщите адрес, и я вам завтра вышлю готовый объектный файл, готовый к употреблению.
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 02.05.06 07:23. Заголовок: Re:
Григорьев Владимир пишет: kniga@online.ru
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 02.05.06 09:55. Заголовок: Re:
/* Translate (Borland C++ 5.2) : BCC -2 -c -ml -O2 -w -X -Z -IC:\BC5\INCLUDE test.c FUNCTIONS: ========= IsNumeric( <nExp> ) --> lNumeric (.t. if number type is NUMERIC) IsFloat( <nExp> ) --> lFloat (.t. if number type is FLOAT) NumLen( <nExp> ) --> nLen (number length from nExp variable) NumDec( <nExp> ) --> nDec (number decimals from nExp variable) where nExp - any valid numeric parameter or expression */ #include <Windows.h> //only declare types #define NUMERIC 0x0002 #define NUM_FLOAT 0x0008 #define ANYNUMBER 0x000A typedef struct { WORD wType; WORD wLen; WORD wDec; WORD wNumber[4]; } CLIPVAR, near * PCLIPVAR; extern PCLIPVAR _param( WORD wParam, WORD wType ); extern void _retni( WORD wNumber ); extern void _retl( BOOL ); void pascal ISNUMERIC( void ) { _retl( _param( 1, NUMERIC ) != 0 ); } void pascal ISFLOAT( void ) { _retl( _param( 1, NUM_FLOAT ) != 0 ); } void pascal NUMLEN( void ) { PCLIPVAR pVar = _param( 1, ANYNUMBER ); _retni( pVar ? pVar->wLen : 0 ); } void pascal NUMDEC( void ) { PCLIPVAR pVar = _param( 1, ANYNUMBER ); _retni( pVar ? pVar->wDec : 0 ); }
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 02.05.06 11:57. Заголовок: Re:
saulius, на самом деле вы указали не совсем корректные функции. Я имею в виду, например, последнюю вашу функцию. цитата: | void pascal NUMDEC( void ) { PCLIPVAR pVar = _param( 1, ANYNUMBER ); _retni( pVar ? pVar->wDec : 0 ); } |
| Дело в том, что часто поле wDec содержит "грязь", так как это поле особенно для типа Long просто не заполняется Clipper-ом, и может содержать что угодно. Поэтому не следует полагаться на то, что вызвав эту вашу функцию, программист получит что-нибудь значещее.
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 02.05.06 12:18. Заголовок: Re:
Лукашевский, получите посылочку.
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 02.05.06 14:01. Заголовок: Re:
поле wLen и wDec обычно содержит "грязь", и программист только получает возможность увидеть, что там находится.
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 02.05.06 14:18. Заголовок: Re:
Для данных типа Long поле wLen, если заполнено, то обычно содержит число 10.
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 02.05.06 16:06. Заголовок: Re:
Для данных типа REAL поле wDec, если заполнено, то обычно содержит число Set(_SET_DECIMALS), а поле wLen, если заполнено, то обычно содержит число 10 + Set(_SET_DECIMALS) + 1.
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 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 при компиляции преобразует их в в константы с плавающей запятой.
|
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 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.
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 04.05.06 13:27. Заголовок: Re:
А как будет с nX := 3000 / 2 nX := 3000 / 3 nX := 3 % 1 ... вывод ?
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 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 при компиляции.
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 05.05.06 07:53. Заголовок: Re:
saulius пишет: Вывод такой, что функциями IsDouble() и IsLong() нужный результат - отличие любого целого числа от любого дробного (которое может быть и с нулевой дробной частью) - не достигается. Более того, я обнаружил, что взятое из поля Numeric размерностью 8 число 9600 воспринимается как Double, что уже неприемлемо.
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 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() вы в любой момент можете сами проверить, какой тип имеет переменная. Что касается первоначальной проблемы, то я думаю, нужно искать другое проектное решение.
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 06.05.06 02:55. Заголовок: Re:
Григорьев Владимир пишет: цитата: | Другое дело, что существуют некоторые ограничение. |
| Тогда уж некоторые ограничениЯ. И главным из которых лично для меня является невозможность определения любого целого числа как целого (даже если оно меньше 32768), если это число извлечено из целочисленного поля типа Numeric DBF-файла, при этом размерность поля, как выяснилось, не играет никакой роли. ЛЮБОЕ ЧИСЛО, ВЗЯТОЕ ИЗ ПОЛЯ, ИМЕЕТ ТИП Double АВТОМАТИЧЕСКИ! В результате смысл использования функций IsLong() и IsDouble() стремится к нулю, ибо отслеживать, как образовывались значения оцениваемых переменных - присвоены они или взяты из поля - практически нереально.
|
|
|
|
| постоянный участник
|
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 06.05.06 11:37. Заголовок: Re:
Как я уже сказал, значит надо по-другому подходить к вопросу проектирования требуемой функциональности. Если поля базы данных Clipper в любом случае считывает в память в виде значений с плавающей запятой, то тогда ваша постановка вопроса становится непонятной и требует уточнения в свете данных обстоятельств. Что вы понимаете под целыми числами и числами с плавающей запятой, у которых дробная часть равна нулю? Откуда появляются эти числа (при какой операции или действии пользователя) или это различие? И т.д. То есть нужно понять, что является источником проблемы и какой проблемы.
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 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, а если дробное (даже с нулевой дробной частью) - то делить не нужно категорически.
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 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
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 08.06.06 10:15. Заголовок: Re:
Хотелось бы узнать, подходит ли мой метод для определения назначенных числу десятичных знаков или эта проблема нерешаема?
|
|
|
|
|
| |
Не зарегистрирован
Зарегистрирован: 01.01.70
|
|
Отправлено: 11.06.06 01:20. Заголовок: Re:
ort пишет: цитата: | Хотелось бы узнать, подходит ли мой метод для определения назначенных числу десятичных знаков |
| Вполне возможно... В самом начале моей бытвы с этой проблемой STR() у меня почему-то выдавал два знака после десятичной точки ВСЕГДА, даже на целое число. Сейчас проверил - всё нормально, для целого результат STR() без точки. Просто фантастика какая-то. Конечно, тогда проверкой на содержание "." в результате STR() вопрос решается!
|
|
|
Ответов - 32
, стр:
1
2
All
[только новые]
|
|