- Код: Выделить всё
nFileSizeHigh as long
nFileSizeLow as long
nFileSizeHigh as long
nFileSizeLow as long
Twister писал(а):Слухай, а что у нас в VB является аналогом int64/ULONGLONG?
Будешь смеяться - не помню
Хакер писал(а):Ничего. Хотя, возможно Currency, а возможно комовский вариантный Decimal.
Интересно, почему ты прихватил Currency, ведь это тоже FP-число, нет?
Fixed-то fixed, но знаковый бит там все же есть
Конечно. Но это решение поставленной ТС'ом задачи. Да ты и сам частенько извращаешься с VB, заставляя его делать то, что он не умеет. Так что нормально.С Date это извращенство.
Twister писал(а):А если ручками записать HiPart в старшие 32 бита double-переменной, а LowPart в младшие?
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
Чтоб я так писал софт...'Итак, даже если наш файл будет
'в шестнадцать с половиной миллионов терабайт,
'мы ошибёмся в 387.08 кб
Хакер писал(а):Жуть. А не проще ли побайтово сравнить?
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
После моего преобразования числа можно сравнивать, перемножать, складывать, делить, выводить результат
Вопрос был мой Я помню. По пути он расширился.Хакер писал(а):Вопрос был в сравнении.
Twister писал(а):Чтоб я так писал софт...
Чем мой вариант не устроил?
Я про комментарий о потере точности.Не уловил иронии
- Код: Выделить всё
Public Type LARGE_INTEGER
HighPart As Long
LowPart As Long
End Type
- Код: Выделить всё
CopyMemory ByVal VarPtr(ValLargeInteger) + 8, L.LowPart, 4
CopyMemory ByVal VarPtr(ValLargeInteger) + 12, L.HighPart, 4
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
Const b14 As Byte = 14
CopyMemory ValLargeInteger, b14, 1
Сейчас этот форум просматривают: AhrefsBot, Google-бот, SemrushBot, Yandex-бот и гости: 63