
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.217.2] |
![]() |
|
Сообщ.
#1
,
|
|
|
В структуре размер файла хранится в двух полях:
![]() ![]() nFileSizeHigh as long nFileSizeLow as long Как это дело перевести, скажем в double, чтобы сравнивать привычными больше-меньше? Или нужен какой-то другой подход? |
![]() |
Сообщ.
#2
,
|
|
Сравнивается тремя ифами
|
Сообщ.
#3
,
|
|
|
ANDLLНу не томи, поясни
![]() |
![]() |
Сообщ.
#4
,
|
|
![]() ![]() function compare(a as xlong, b as xlong) as integer compare=sgn(a.high-b.high) if compare=0 then compare=sgn(a.low-b.low) end function |
Сообщ.
#5
,
|
|
|
Akina
Спасибо! То что надо ![]() А как бы ещё этот xlong перевести в более привычный вид? И какой тип выбрать? дабла ведь не хватит... Может, в вариант? Скажем, 10 гигов записать xlong-ом? узнать по xlong-у, сколько это гигов? |
![]() |
Сообщ.
#6
,
|
|
Ты вообще представляешь что эти два члена в структуре "символизируют"?
|
Сообщ.
#7
,
|
|
|
ANDLLЯ представляю
![]() На сколько я понимаю, оба поля ведь беззнаковые? А раз беззнаковых лонгов в бейсике нет, то отрицательные - больше положительных, и самое большое, которое влазит в лонг - минус 1. То есть &Hffffffff - самое большое число, которое можно записать в один лонг (нужно ещё держать в уме, что на самом деле оно не отрицательное). Прибавляем единичку - получаем переполнение лонга в верхний лонг: &h100000000 и так далее до &hffffffffffffffff Теоретически это понимая, мне очень сложно абстагироваться, я запутываюсь - хочется оперировать привычными десятичными числами без ограничения числа знаков ![]() |
![]() |
Сообщ.
#8
,
|
|
Ясно
А какова все же цель? Нужно (с потерей данных) преобразовать в double или в string(например что бы пользователю показать) но без потерь? Добавлено А впрочем пофиг, все равно в три строчки не получается Добавлено Цитата Артур @ На сколько я понимаю, оба поля ведь беззнаковые? А раз беззнаковых лонгов в бейсике нет, то отрицательные - больше положительных, и самое большое, которое влазит в лонг - минус 1. То есть &Hffffffff - самое большое число, которое можно записать в один лонг (нужно ещё держать в уме, что на самом деле оно не отрицательное). Прибавляем единичку - получаем переполнение лонга в верхний лонг: &h100000000 и так далее до &hffffffffffffffff я бы сделал так: function ltod(byval x as long) as double if x < 0 then ltod = 2#^32 +cdbl(x) else ltod = x endif end func function lltod(high as long, low as long) as double lltod = ltod(high) * (2#^32) + ltod(low) end function |
Сообщ.
#9
,
|
|
|
В функцию нужно передать минимум и максимум, а вернуть - принадлежит ли размер этому диапазону. Предполагаю определить аргументы минимум и максимум как вариант, ведь:
Цитата Переменные типа Decimal сохраняются как 96-разрядные (12-байт) целые без знака, масштабируемые степенями 10. Степень масштабирования определяет число знаков дробной части, которое может изменяться от 0 до 28. Для степени масштабирования 0 (числа без дробной части), максимальными по абсолютной величине значениями являются +/-79 228 162 514 264 337 593 543 950 335. При 28 знаках дробной части максимальными по абсолютной величине значениями являются +/-7,9228162514264337593543950335, а минимальными +/-0,0000000000000000000000000001. Примечание. В настоящее время поддерживается использование типа данных Decimal только в пределах типа Variant, т.е. невозможно описать переменную с типом Decimal. Пользователь, однако, имеет возможность создать переменную типа Variant с подтипом Decimal с помощью функции CDec. но что-то как то смутно понимаю смысл этой цитаты ![]() Или я не туда рою? |
![]() |
Сообщ.
#10
,
|
|
Если нужно вернуть принадлежит ли диапазону то чем мешает функция в посте номер 3?
|
Сообщ.
#11
,
|
|
|
Цитата ANDLL @ ![]() ![]() function lltod(high as long, low as long) as double lltod = ltod(high) * (2#^32) + ltod(low) end function Цитата ANDLL @ Нужно (с потерей данных) преобразовать в double? А на каком размере начнётся потеря, не могу сообразить? Где-нибудь далеко за террабайты и этим можно пока пренебречь за неимением файлов таких размеров? Или потери начнутся раньше? |
![]() |
Сообщ.
#12
,
|
|
Проверь сам
for i = 0.... |
Сообщ.
#13
,
|
|
|
Цитата ANDLL @ Если нужно вернуть принадлежит ли диапазону то чем мешает функция в посте номер 3? Тем, что в аргумент нужно будет передавать уже xlong, а хотелось бы что-то более привычное То есть, передавать-то можно как раз xlong, но этот ХЛонг нужно сначала получить. Скажем, 10 гигов - это сколько в ХЛонге? |
![]() |
Сообщ.
#14
,
|
|
6, 0
|
![]() |
Сообщ.
#15
,
|
|
Ну способ "в лоб":
![]() ![]() Declare Function CopyMemory Lib "kernel32" (dst As Any, src As Any, ByVal length As Long) Function Compare(n1 As LARGE_INTEGER, n2 As LARGE_INTEGER) Dim b1() As Long, b2() As Long, i As Long Redim b1(0 To Len(n1)), b2(0 To Len(n2)) CopyMemory b1(0), n1, Len(n1) CopyMemory b2(0), n2, Len(n2) For i = 0 To Len(n1) Compare = Sgn(b1(i) - b2(i)) If Compare <> 0 Then Exit Function Next End Function ох уж этот Бэйсик... |
Сообщ.
#16
,
|
|
|
![]() ![]() Sub Main() Dim v, i As Integer, d As Double v = CDec(1) For i = 1 To 64 v = v * 2 Next d = v Debug.Print v Debug.Print d End Sub В общем, потеря данных не в количестве, а только в точности ![]() ![]() Добавлено ALXR То есть, предлагаешь сравнить байт за байтом? А чем плох способ из четвертого поста? Добавлено ALXR Кстати, а это мысль ![]() ![]() ![]() Private Type LARGE_INTEGER b(7) As Byte End Type Или здесь есть какие-нибудь грабли? Добавлено Кстати, ![]() ![]() v = CDec("123456789123456789123456789") ![]() |
![]() |
Сообщ.
#17
,
|
|
LARGE_INTEGER выглядит так:
![]() ![]() Type LARGE_INTEGER dwLow As Long dwHigh As Long End Type Предполагаю, что если его объявить как b(7) As Byte, то пользоваться (в остальных случаях) им будет неудобно. Цитата ALXR То есть, предлагаешь сравнить байт за байтом? А чем плох способ из четвертого поста? Тем, что Long в VB знаковый и могут возникнуть нюансы. Впрочем, byte тоже знаковый (кажется) и надо делать дополнительные проверки. |
Сообщ.
#18
,
|
|
|
Цитата ALXR @ Впрочем, byte тоже знаковый (кажется) и надо делать дополнительные проверки ![]() ![]() ? CBYTE(&HFF) 255 |
![]() |
Сообщ.
#19
,
|
|
byte беззнаковый
|
![]() |
Сообщ.
#20
,
|
|
Ну тогда вопрос с проверками отваливается. Код должен работать.
|
![]() |
Сообщ.
#21
,
|
|
У тебя код лонгов
|
Сообщ.
#22
,
|
|
|
Цитата ALXR @ Цитата А чем плох способ из четвертого поста? Тем, что Long в VB знаковый и могут возникнуть нюансы. Мне кажется, в коде Akina это учтено... На вскидку, по крайней мере. Кстати, я таки дорешал: ![]() ![]() Option Explicit Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long) Public Type LARGE_INTEGER HighPart As Long LowPart As Long End Type Sub Main() Dim v, i As Integer, maxLgInt 'Сотворим самое большое число, которое поместится 'в восьмибайтное целое беззнаковое: v = CDec(1) maxLgInt = CDec(&HF) For i = 1 To 15 v = v * 16 maxLgInt = maxLgInt + v * 15 Next Debug.Print maxLgInt 'Выводится: ' 18446744073709551615 'проверяем инженерным калькулятором: 'FFFFFFFFFFFFFFFF = 18446744073709551615 'Как в аптеке :) 'Это у нас столько байт. Переводим в терабайты: '18446744073709551615 Б = 16 777 216 ТБ Dim d As Double d = maxLgInt ' Это же число в дабле Debug.Print CDec(d) ' переводим опять в Decimal, 'чтобы посмотреть, что потеряли 'Выводится: '18446744073709600000 'Потеряли 48385 байт или 387.08 кб 'Итак, даже если наш файл будет 'в шестнадцать с половиной миллионов терабайт, 'мы ошибёмся в 387.08 кб 'Так что для обозримых файлов точности дабл вполне хватит :) 'Но если точность всё-таки понадобится... 'Посмотрим, как в варианте хранится 'наше восьмибайтное целое беззнаковое: Dim b(15) As Byte CopyMemory b(0), maxLgInt, 16 Stop 'смотрим содержимое b и видим: нулевой байт=14, 'само число начиная с 8-го байта и до 15-го 'Остальные просто нули 'Осталось написать функции перевода туда-сюда: 'ValLargeInteger будет делать из LARGE_INTEGER 'число в привычном виде 'getLargeInteger будет переводить число '(можно числом, строкой, можно в Hex-формате) 'в тип LARGE_INTEGER 'Сотворим самодельную константу &HFFFFFFFFFFFFFFFF Dim L As LARGE_INTEGER L.HighPart = &HFFFFFFFF L.LowPart = &HFFFFFFFF Dim MAX_LARGE_INTEGER MAX_LARGE_INTEGER = ValLargeInteger(L) Debug.Print MAX_LARGE_INTEGER 'всё получилось :) Stop 'Ещё один эксперемент: 'берём шестрадцатиричное число 123456789ABCDEF0 'Вызываем инженерный калькулятор и переводим в десятично: '1311768467463790320 'А теперь нашу функцию: L.HighPart = &H12345678 L.LowPart = &H9ABCDEF0 Debug.Print " 1311768467463790320" 'столько получилось на калькуляторе Debug.Print ValLargeInteger(L) ' сходится :) 'А теперь - обратная функция: L = getLargeInteger("&HFECDA9876543210") 'проверяем: Debug.Print CDec("&HFECDA9876543210") Debug.Print ValLargeInteger(L) 'Опять сошлось :) End Sub Function ValLargeInteger(L As LARGE_INTEGER) As Variant CopyMemory ValLargeInteger, 14, 1 'первый байт 14 CopyMemory ByVal VarPtr(ValLargeInteger) + 8, L.LowPart, 4 CopyMemory ByVal VarPtr(ValLargeInteger) + 12, L.HighPart, 4 End Function Function getLargeInteger(ByVal ValLargeInteger As Variant) As LARGE_INTEGER ' можно передать число строкой или числом ValLargeInteger = CDec(ValLargeInteger) If ValLargeInteger > CDec("&HFFFFFFFFFFFFFFFF") Then Err.Raise 6 If ValLargeInteger < 0 Then Err.Raise 6 CopyMemory getLargeInteger.HighPart _ , ByVal VarPtr(ValLargeInteger) + 12, 4 CopyMemory getLargeInteger.LowPart _ , ByVal VarPtr(ValLargeInteger) + 8, 4 End Function Добавлено Посмотрите, кому не лень - остались ли здесь какие грабли? |
![]() |
Сообщ.
#23
,
|
|
Кстати, код из четвертого поста неверен
|
Сообщ.
#24
,
|
|
|
А мой?
|
Сообщ.
#25
,
|
|
|
Тьфу ты ну ты, косяк косячный
![]() ![]() Исправляюсь: ![]() ![]() Public Type LARGE_INTEGER LowPart As Long HighPart As Long End Type '------------------------------------------------------------ Function ValLargeInteger(L As LARGE_INTEGER) As Variant CopyMemory ValLargeInteger, 14, 1 'первый байт 14 CopyMemory ByVal VarPtr(ValLargeInteger) + 8, L, 8 End Function '------------------------------------------------------------ Function getLargeInteger(ByVal ValLargeInteger As Variant) As LARGE_INTEGER ' можно передать число строкой или числом ValLargeInteger = CDec(ValLargeInteger) If ValLargeInteger > CDec("18446744073709551615") Then Err.Raise 6 If ValLargeInteger < 0 Then Err.Raise 6 CopyMemory getLargeInteger _ , ByVal VarPtr(ValLargeInteger) + 8, 8 End Function |
![]() |
Сообщ.
#26
,
|
|
Цитата ANDLL @ У тебя код лонгов Хм. Хочется извращенцам, которые начинают лезть в дебри на VB, посоветовать переходить на языки другого уровня. Не вижу необходимости использовать язык, предназначенный совершенно для совершенно иных целей, в таких случаях. Аргументирую (для себя) это только ленью авторов программ. |
Сообщ.
#27
,
|
|
|
Такая мелочь, как "получить размер файла" - это дебри?
|
Сообщ.
#28
,
|
|
|
Возвращаясь к изначальной задачи - если нужно-таки просто сравнить, не вникая, что там за числа внутри. Тремя ифами я, конечно, не обошелся
![]() ![]() ![]() 'Помним, что раз числа беззнаковые, то отрицательные больше положительных, а самое большое -1 Do Select Case H1 Case H2 ' верхние лонги равны, нужно сравнить нижние Case Is < 0 If H2 < 0 Then 'оба отрицательные, просто сравниваем If H1 > H2 Then comp = 1 Else comp = -1 Else 'H2 положительное, а значит меньше отрицательного H1 comp = 1 End If Exit Do Case Else If H2 >= 0 Then 'оба положительные, просто сравниваем If H1 > H2 Then comp = 1 Else comp = -1 Else comp = -1 End If Exit Do End Select ' если не вышли из ду, то нужно сравнить нижние лонги. Точно так же Select Case L1 Case L2 ' нижние лонги тоже равны, числа равны Case Is < 0 If L2 < 0 Then 'оба отрицательные, просто сравниваем If L1 > L2 Then comp = 1 Else comp = -1 Else 'L2 положительное, а значит меньше отрицательного L1 comp = 1 End If Case Else If L2 >= 0 Then 'оба положительные, просто сравниваем If L1 > L2 Then comp = 1 Else comp = -1 Else comp = -1 End If End Select Loop While False Добавлено Укомпактил так: ![]() ![]() Do If H1 > H2 Then If (H1 < 0) Xor (H2 < 0) Then comp = -1 Else comp = 1 Exit Do ElseIf H1 < H2 Then If (H1 < 0) Xor (H2 < 0) Then comp = 1 Else comp = -1 Exit Do End If If L1 > L2 Then If (L1 < 0) Xor (L2 < 0) Then comp = -1 Else comp = 1 ElseIf L1 < L2 Then If (L1 < 0) Xor (L2 < 0) Then comp = 1 Else comp = -1 End If Loop While 0 |
![]() |
Сообщ.
#29
,
|
|
Цитата Артур @ Такая мелочь, как "получить размер файла" - это дебри? Учитывая наличие функции CompareFileTime в WINAPI, структура которой FILETIME полностью идентична структуре LARGE_INTEGER, то все вышеописанное я бы назвал дебрями. |
Сообщ.
#30
,
|
|
|
Учитывая, что такая структура используется не только для размера файла, я бы назвал вышеописанное стандартной ситуацией
![]() |
![]() |
Сообщ.
#31
,
|
|
Код из сообщения #28? Стандартная ситуация?
|
Сообщ.
#32
,
|
|
|
Раз в языке нет длинных беззнаковых, а нужно, значит достаточно стандартная. Особого напряжения ума и каких-то глубоких изощрённых подходов там, вроде нет - где дебри? Всё понятно и более-менее очевидно.
|
![]() |
Сообщ.
#33
,
|
|
Раз в языке нет длинных беззнаковых чисел, то:
1. Они там, скорее всего, не нужны. 2. Язык устарел. 3. Следствие из 2-го: На нем хорошо учиться программированию и как можно скорее переходить на другой (если в планах есть продолжать). |
Сообщ.
#34
,
|
|
|
ALXR
С этим согласен. Но если есть большой проект, в который вбухано много времени и сил, и который теперь уже практически нереально перевести на другой язык (а другой язык сначала нужно ещё и изучить ![]() ![]() |
![]() |
Сообщ.
#35
,
|
|
Да никто же не спорит.
![]() Каждый сам кузнец своей оградки. ![]() |
Сообщ.
#36
,
|
|
|
Цитата ALXR @ Речь о том, что есть одна ф-ция, которая занимается тем, что требуется в теме. Какая? |