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
ссылка на сообщение  Отправлено: 26.04.06 08:19. Заголовок: Re:


x:=10.00000001
y:=int(x)
? x==y


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


Не зарегистрирован
Зарегистрирован: 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.

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



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


Именно "как отличить изначальное целое число от дробного результата каких-либо вычислений" я делаю так:
проверяю CEILING() равно FLOOR()? Это из CLIPPER TOOLS II
Одна функция округляет до ближайшего большего целого, другая - до ближайшего меньшего целого. Если они равны, то значит и аргумент целый.

Спасибо: 0 





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


CEILING() и FLOOR() я, конечно, попробую, но подозреваю, что разницу между 10 и 10.000 они мне не покажут... В том-то и проблема, что в дробной части могут быть сплошные нули, а определить, что это число не целое, а "как бы дробное", необходимо.

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





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


Dima пишет:

 цитата:
x:=10.00000001
y:=int(x)
? x==y


Дима, ты, наверное, не понял сути проблемы. А она в том, что в функцию, которая может быть вызвана из десятка мест в программе, приходит параметр, и если он целое число, то его нужно перед дальнейшими действиями в этой функции разделить на 1000, а если дробное, то оставить как есть. Проблема в том, что дробное число может быть и 10.000, т.е. в десятичных знаках могут быть одни нули, НО: число от этого не перестаёт быть дробным, и на 1000 его делить, соответственно, категорически не нужно...

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





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


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

 цитата:
Но, я уже не помню, где-то внутри Clipper я встречал функцию, которая четко заносит в Decimals число десятичных знаков для данного внутреннего представления Double.


Осталось только понять, как называется эта функция, а также как из Clipper получить доступ к значению Decimals

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



Не зарегистрирован
Зарегистрирован: 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() даст ответ на вопрос, како же в итоге внутренний рузультат получился?

Спасибо: 0 
постоянный участник


Не зарегистрирован
Зарегистрирован: 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




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


Не зарегистрирован
Зарегистрирован: 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



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



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


if At('.', Str(NUM))> 0
//REAL
else
//INTEGER
endif

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





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


MikeP пишет:

 цитата:
Возможно str() даст ответ на вопрос, како же в итоге внутренний рузультат получился?


Не знаю, не знаю... У меня STR(целое число) выдаёт результат с двумя нулями после точки...

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





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


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

 цитата:
Написать самому функцию типа IsLong( nNumParm ).


К сожалению, ни в асссемблере, ни в C программить не умею

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


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


Лукашевский

 цитата:
К сожалению, ни в асссемблере, ни в C программить не умею


Сообщите адрес, и я вам завтра вышлю готовый объектный файл, готовый к употреблению.


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





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


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

 цитата:
Сообщите адрес


kniga@online.ru

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



Не зарегистрирован
Зарегистрирован: 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 );
}

Спасибо: 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-ом, и может содержать что угодно. Поэтому не следует полагаться на то, что вызвав эту вашу функцию, программист получит что-нибудь значещее.

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


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


Лукашевский, получите посылочку.


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



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


поле wLen и wDec обычно содержит "грязь", и программист только получает возможность увидеть,
что там находится.


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


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


Для данных типа Long поле wLen, если заполнено, то обычно содержит число 10.

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



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


Для данных типа REAL поле wDec, если заполнено, то обычно содержит число
Set(_SET_DECIMALS),
а поле wLen, если заполнено, то обычно содержит число
10 + Set(_SET_DECIMALS) + 1.

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


Не зарегистрирован
Зарегистрирован: 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 час. Хитов сегодня: 105
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет