Имя: Пароль:
1C
 
Запрос через COM выдаёт 10,68999999 вместо 10,69
0 DirecTwiX
 
23.09.14
11:34
Пробовал использовать ВЫРАЗИТЬ КАК ЧИСЛО (15, 2) - результат тот же. Кто-нибудь сталкивался? Как бороться?

1С:Предприятие 8.3 (8.3.5.1119)
1 ДенисЧ
 
23.09.14
11:34
Это норма.
Округляй при получении.
2 DirecTwiX
 
23.09.14
11:37
(1) Это беда..


ЗаполнитьЗначенияСвойств(Отбор, выборка);
ВыборкаБП.Сбросить();
Если не выборкаБП.НайтиСледующий(Отбор) Тогда


Ладно, спасибо!
3 vasbur
 
23.09.14
11:47
(1) (2) это float
4 stix2010
 
23.09.14
11:49
Выразить Как Строка
5 Serginio1
 
23.09.14
11:50
Вообще странно, так как Decimal прекрасно передается через COM.
Передавай как строку
6 DirecTwiX
 
23.09.14
11:53
Вариант. Спасибо!



Я пытался... :@

Функция ОкруглитьТЗ(тз, Колонки, Разрядность = 2)
    Структ = Новый Структура(Колонки);
    Для каждого Стр Из тз Цикл
        Для каждого КлЗн Из Структ Цикл
            Стр[КлЗн.Ключ] = Окр(Стр[КлЗн.Ключ], Разрядность);    
        КонецЦикла;     
    КонецЦикла;
    Запрос = Новый Запрос;
    Запрос.Текст = "выбрать * поместить ВТ из &тз КАК ТЗ; Выбрать * ИЗ ВТ КАК ВТ";
    Запрос.УстановитьПараметр("тз", тз);
    РезультатЗапроса = Запрос.Выполнить();
    
    Возврат РезультатЗапроса;
КонецФункции

Правда
Стр[КлЗн.Ключ] = Окр(Стр[КлЗн.Ключ], Разрядность);
Всё равно не работает -.-
7 DirecTwiX
 
23.09.14
11:56

Несовместимые типы "ВЫРАЗИТЬ"
<<?>>Выразить (СУММА(ВТ.ЗП) как Строка(100))
8 bolobol
 
23.09.14
11:58
Выразить-то надо как число 15,2!
9 DirecTwiX
 
23.09.14
12:07
(8) В (0) писал, что уже пробовал..

Тем не менее, победа :)

Выразить (СУММА(ВТ.ЗП)*100 как Число(17))
10 Мыш
 
23.09.14
12:07
(0) Это известная трабла. Проблема не в 1С. Проблема в COM )
11 Serginio1
 
23.09.14
12:16
(10) Проблема в 1С ибо Decimal прекрасно передается через COM http://rsdn.ru/article/com/varsafearr.xml#EZF
12 Мыш
 
23.09.14
12:30
(11) Борис, ты не прав ) Если сом отдает не децимал, а вариант, то 1С тут ничо не может сделать.
13 Serginio1
 
23.09.14
12:41
(12) Сом всегда передает Вариант.  А вот внутри варианта прекрасно уживается Децимал. Я тебе ссылку для чего приводил?
А вот 1С в вариант устанавливает double
14 Torquader
 
23.09.14
15:37
(13) Внутри Variant Decimal живёт с огромными костылями, так как стандартом не является, а просто занимает всю структуру Variant.
Другое дело, что Currency (то есть восемь байт на целое число, сдвинутое на четыре разряда) прекрасно живёт в OLE и никогда нигде не теряется.

Но, стандарт общения между программами по OLE предписывает использовать Double для чисел с плавающей или фиксированной точкой и Long для целых чисел.

В том же Excel мы имеем такие же грабли, только ещё и значение в ячейке может быть "округлено".

P.S. можно умножить на 100 и выразить как целое число - по идее, должен передать как целое, но если оно за пределы Long вылезет, то опять же - будет Double, так как Decimal или Currency нужно указывать специально (1С-то этого не умеет).
15 Torquader
 
23.09.14
15:39
+
В VbScript, например, можно полученный результат преобразовать CCur(Value) и мы получим значение без округления. Конечно, есть вероятность, что там что-то потеряется (если передавать номер счёта как число, то Currency просто уже не хватит), но намного меньше.
16 Torquader
 
23.09.14
15:41
+
У меня спасало Ole.String(Запрос.ИмяПоля) - преобразование в строку шло ещё до начала работы с OLE, но 1С настолько криво преобразует число в строку.
17 DmitrO
 
23.09.14
15:43
(14) "живёт с огромными костылями"???
VT_DECIMAL не является стандартом???
хренова гора функций decimal арифметики и преобразований в/из decimal расположенных в системных OLE библиотеках windows это случайность???
18 Torquader
 
23.09.14
16:36
Чего-то посмотрел в исходники:
VariantToInt32, VariantToInt64, VariantToDouble, VariantToGuid

чего-то там нет VariantToDecimal собственно как и VariantToCurrency.

Просто, если бы в 1С делали правильно, то могли бы вообще определить свой тип данных, так как они используют внутренние представления чисел более сложные, чем Variant и передавать их по OLE спокойно через структуры, но они пошли по простому пути, а самый простой путь - это Double, так как вся работа с ним выполняется сопроцессором (в отличие от Decimal, для которого нужна специальная библиотека).
19 Torquader
 
23.09.14
16:41
И, самое главное, Microsoft Script Control и VbScript не поддерживают Decimal вообще.
И вообще, прямым языком написано, если вы перемножаете два целых числа, то результатом может быть значение типа Double - почему-то не Int64 и не Decimal или Currency, а именно Double.
Вполне вероятно, что выполняя внутренние преобразования своих чисел к переменной Variant 1С использует стандартные библиотеки, которые именно так и работают.
20 DmitrO
 
23.09.14
16:47
21 Serginio1
 
23.09.14
16:48
(14) Живет без костылей http://rsdn.ru/article/com/varsafearr.xml#EZF

1С 8.2 прекрасно понимает Decimal. Специально делал тесты.
22 DmitrO
 
23.09.14
17:07
8ка нормально принимает все типы VARIANT, в том числе и VT_DECIMAL (можно проверить например через ADODB), и даже VT_UNKNOWN.

Однако у них плохо написан COMConnector (V8.Application, V8C.Application тоже) дело в том что они свои числа выдают как VT_R8 (double), если число имеет дробную часть.

А сделано это вероятно для того чтобы с этими COM серверами можно было работать из 7ки, ибо она не принимает VT_DECIMAL.
23 DmitrO
 
23.09.14
17:15
Внутренние данные чисел 1C (и 7ой и 8ой) отличаются от данных хранимых в VARIANT типа VT_DECIMAL, они хранятся по другому, однако наиболее близкое представление это именно VT_DECIMAL, числа 1С только могут быть больше.
Поэтому арифметика (имею в виду функции) у них собственная.
24 Fragster
 
гуру
23.09.14
17:18
В запросе использовать функцию Представление, тогда в результате будет строка, причем которую функция "число()"  должна вроде как сожрать
25 DmitrO
 
23.09.14
17:20
(24)представление будет зависеть от локализации сеанса
26 DmitrO
 
23.09.14
17:25
Им (1С) надо в COMConnector (в свои COM сервера) дописать примерно такое свойство ReturnNumericsAs со значениями {Real, Decimal}, но это же такие пустяки.. :)
27 Serginio1
 
23.09.14
18:04
(26) Что я например и сделал для доступа к классам .Net
Правда я перевожу все в строку для инвариантного языка
.ToString(CultureInfo.InvariantCulture);
А в 7 ке таких типов куча

if (ЭтоСемерка)
                {
                    Тип = obj.GetType();
                    if (Тип == typeof(System.Decimal)) return ((Decimal)obj).ToString(CultureInfo.InvariantCulture);
                    if (Тип.IsPrimitive)
                    {
                        if ((Тип == typeof(System.Int64) || Тип == typeof(System.UInt32) || Тип == typeof(System.UInt64) || Тип == typeof(System.UInt16) || Тип == typeof(System.SByte)))
                            obj = Convert.ChangeType(obj, typeof(string), CultureInfo.InvariantCulture);
                    }
28 Torquader
 
23.09.14
18:38
(27) Собственно говоря, любое число можно вообще в виде 16-ричной строки записать, как Dump памяти.
Просто на это будет тратится машинное время.
И, самое печальное, что ни "осёл" ни VbScript корректно с Decimal не работают.

(22) А точно 1С понимает именно Decimal, а не просто переводит его в Double сразу при получении, например, VariantChangeType прекрасно может преобразовывать типы, про которые получатель ничего не знает - нужно лишь чтобы система умела выполнить преобразование.
29 Serginio1
 
23.09.14
18:49
(28) Да. Получает то она вариант с Decimal.
Я специально проверял типы
public object ПолучитьМассивТипов()
        {
            var list = new List<object>();
            list.Add("System.String");
            list.Add(AutoWrap.ОбернутьОбъект(DateTime.Now));
            list.Add(AutoWrap.ОбернутьОбъект(true));
            list.Add(AutoWrap.ОбернутьОбъект((System.Byte)45));
            list.Add(AutoWrap.ОбернутьОбъект((System.Decimal)48.789));
            list.Add(AutoWrap.ОбернутьОбъект((System.Double)51.51));
            list.Add(AutoWrap.ОбернутьОбъект((System.Single)11.11));
            list.Add(AutoWrap.ОбернутьОбъект((System.Int32)11));
            list.Add(AutoWrap.ОбернутьОбъект((System.Int64)789988778899));
            list.Add(AutoWrap.ОбернутьОбъект((System.SByte)45));
            list.Add(AutoWrap.ОбернутьОбъект((System.Int16)66));
            list.Add(AutoWrap.ОбернутьОбъект((System.UInt32)77));
            list.Add(AutoWrap.ОбернутьОбъект((System.UInt64)88888888888888));
            list.Add(AutoWrap.ОбернутьОбъект((System.UInt16)102));

            return new AutoWrap(list);
        }
30 Serginio1
 
23.09.14
18:49
И выдавал именно те значения которые и передавались
31 Chai Nic
 
23.09.14
19:03
А в чем проблема.. обертывай таблицу значений результата запроса в строку и передавай через COM.. Через комбинацию ЗначениеВСтрокуВнутр/ЗначениеИзСтрокиВнутр.. Костыли, но достаточно удобные.
32 Serginio1
 
24.09.14
10:09
(28) Кстати есть поддержка в
Синтаксис:

Новый COMSafeArray(<ТипЭлемента>, <<разм0>,...,<размN-1>>)
Параметры:

<ТипЭлемента> (обязательный)

Тип: Строка.
Определяет тип элемента COMSafeArray.
Тип элемента задается строкой и может принимать одно из следующих значений:
VT_I1 - знаковое целое 1 байт;
VT_I2 - знаковое целое 2 байта;
VT_I4 - знаковое целое 4 байта;
VT_I8 - знаковое целое 8 байт;
VT_INT - знаковое целое;
VT_UI1 - беззнаковое целое 1 байт;
VT_UI2 - беззнаковое целое 2 байта;
VT_UI4 - беззнаковое целое 4 байта;
VT_UI8 - беззнаковое целое 8 байт;
VT_UINT - беззнаковое целое;
VT_R4 - действительное число 4 байта;
VT_R8 - действительное число 8 байт;
VT_DECIMAL - десятичное число с фиксированной точкой 12 байт;
VT_CY - значение денежного типа;
VT_DATE - значение типа дата;
VT_BSTR - значение типа строка;
VT_DISPATCH - указатель на интерфейс IDispatch;
VT_ERROR - код ошибки;
VT_BOOL - значение логического типа;
VT_UNKNOWN - указатель на интерфейс IUnknown;
VT_VARIANT - вариантный тип.
33 Torquader
 
24.09.14
10:14
И ещё вопрос - как число хранится в SQL-сервере ?
Просто, есть вероятность, что округление происходит как раз в момент получения данных из SQL-сервера, а не при передаче по OLE.
Не стоит забывать, что при выводе числа дробная часть по умолчанию, округляется до 6 знаков.
34 Serginio1
 
24.09.14
10:40
(33) decimal и numeric (Transact-SQL)

http://msdn.microsoft.com/ru-ru/library/ms187746.aspx
35 Torquader
 
24.09.14
23:48
(34) Так как раз и написано, что 17 знаков - то есть Double и округление - так что есть подозрение, что именно на этом моменте знаки и теряются.
decimal и numeric - это слова для описания чисел, а не типы.
36 Serginio1
 
24.09.14
23:56
(35) Это типы. Там кстати написано
When converting float or real values to decimal or numeric, the decimal value will never have more than 17 decimals.


decimal [ (p[ ,s] )] и numeric[ (p[ ,s] )]
Числа с фиксированной точностью и масштабом. При использовании максимальной точности числа могут принимать значения в диапазоне от -10^38+1 до 10^38-1. Синонимами по стандарту ISO для decimal являются dec и dec(p, s). numeric функционально эквивалентно decimal.
p (точность)
Максимальное количество десятичных разрядов числа (как слева, так и справа от десятичной запятой), которые будут храниться. Точность должна быть значением в диапазоне от 1 до максимум 38. Точность по умолчанию составляет 18.
s (масштаб)
Максимальное количество хранимых десятичных разрядов числа справа от десятичной запятой. Это число отнимается от p для определения максимального количества цифр слева от десятичной запятой. Максимальное количество десятичных разрядов числа справа от десятичной запятой. Масштаб может принимать значение от 0 до p. Масштаб может быть указан только совместно с точностью. По умолчанию масштаб принимает значение 0; поэтому 0 <= s <= p. Максимальный размер хранилища зависит от точности.
37 Cube
 
25.09.14
05:23
38 Torquader
 
26.09.14
20:58
Кстати, а если попробовать задать числу 20 целых знаков, то есть (20,2), чтобы оно гарантированно в Double не влезла.
Закон Брукера: Даже маленькая практика стоит большой теории.