На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела Visual Basic: Общие вопросы
Здесь обсуждаются вопросы по языку Visual Basic 1-6 (а так же по схожим языкам, как, например, PowerBASIC).
Вопросы по Visual Basic .NET (это который входит в состав Visual Studio 2002/2003/2005/2008+, для тех, кто не в курсе) обсуждаются в разделе .NET.

Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что Вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются. Студенты, вам сюда: ПОМОЩЬ СТУДЕНТАМ!
4. Используйте теги [ code=vba ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Формулируйте свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной (и более) давности, без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта user posted image FAQ Раздела user posted image Кладовка user posted image Наши Исходники user posted image API-Guide user posted image Поиск по Разделу user posted image MSDN Library Online user posted image Google

Ваше мнение о модераторах: user posted image SCINER, user posted image B.V.
Модераторы: SCINER, B.V.
  
> Сравнение больших чисел
    В структуре размер файла хранится в двух полях:

    ExpandedWrap disabled
      nFileSizeHigh as long
      nFileSizeLow as long


    Как это дело перевести, скажем в double, чтобы сравнивать привычными больше-меньше? Или нужен какой-то другой подход?
      Сравнивается тремя ифами
        ANDLLНу не томи, поясни :)
          ExpandedWrap disabled
            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
            Akina
            Спасибо! То что надо :D
            А как бы ещё этот xlong перевести в более привычный вид? И какой тип выбрать? дабла ведь не хватит... Может, в вариант?

            Скажем, 10 гигов записать xlong-ом? узнать по xlong-у, сколько это гигов?
              Ты вообще представляешь что эти два члена в структуре "символизируют"?
                ANDLLЯ представляю :) Но именно что представляю - без подробностей, потому и спрашиваю.

                На сколько я понимаю, оба поля ведь беззнаковые? А раз беззнаковых лонгов в бейсике нет, то отрицательные - больше положительных, и самое большое, которое влазит в лонг - минус 1. То есть &Hffffffff - самое большое число, которое можно записать в один лонг (нужно ещё держать в уме, что на самом деле оно не отрицательное). Прибавляем единичку - получаем переполнение лонга в верхний лонг: &h100000000 и так далее до &hffffffffffffffff

                Теоретически это понимая, мне очень сложно абстагироваться, я запутываюсь - хочется оперировать привычными десятичными числами без ограничения числа знаков :)
                  Ясно
                  А какова все же цель? Нужно (с потерей данных) преобразовать в 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
                    В функцию нужно передать минимум и максимум, а вернуть - принадлежит ли размер этому диапазону. Предполагаю определить аргументы минимум и максимум как вариант, ведь:

                    Цитата
                    Переменные типа 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.

                    но что-то как то смутно понимаю смысл этой цитаты :blush: Не говоря уже о том, чтобы перевести введенное число в xLong

                    Или я не туда рою?
                      Если нужно вернуть принадлежит ли диапазону то чем мешает функция в посте номер 3?
                        Цитата ANDLL @
                        ExpandedWrap disabled
                          function lltod(high as long, low as long) as double
                          lltod = ltod(high) * (2#^32) + ltod(low)
                          end function


                        Цитата ANDLL @
                        Нужно (с потерей данных) преобразовать в double?

                        А на каком размере начнётся потеря, не могу сообразить? Где-нибудь далеко за террабайты и этим можно пока пренебречь за неимением файлов таких размеров? Или потери начнутся раньше?
                          Проверь сам
                          for i = 0....
                            Цитата ANDLL @
                            Если нужно вернуть принадлежит ли диапазону то чем мешает функция в посте номер 3?

                            Тем, что в аргумент нужно будет передавать уже xlong, а хотелось бы что-то более привычное То есть, передавать-то можно как раз xlong, но этот ХЛонг нужно сначала получить. Скажем, 10 гигов - это сколько в ХЛонге?
                              6, 0
                                Ну способ "в лоб":
                                ExpandedWrap disabled
                                  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


                                ох уж этот Бэйсик...
                                  ExpandedWrap disabled
                                    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

                                  В общем, потеря данных не в количестве, а только в точности :) В общем, пойдёт дабл :D

                                  Добавлено
                                  ALXR То есть, предлагаешь сравнить байт за байтом? А чем плох способ из четвертого поста?

                                  Добавлено
                                  ALXR
                                  Кстати, а это мысль :) Можно же объявить тип LARGE_INTEGER как:
                                  ExpandedWrap disabled
                                    Private Type LARGE_INTEGER
                                       b(7) As Byte
                                    End Type

                                  Или здесь есть какие-нибудь грабли?

                                  Добавлено
                                  Кстати,
                                  ExpandedWrap disabled
                                    v = CDec("123456789123456789123456789")
                                  решает вопрос о вводе больших чисел строкой :)
                                    LARGE_INTEGER выглядит так:
                                    ExpandedWrap disabled
                                      Type LARGE_INTEGER
                                        dwLow As Long
                                        dwHigh As Long
                                      End Type

                                    Предполагаю, что если его объявить как b(7) As Byte, то пользоваться (в остальных случаях) им будет неудобно.

                                    Цитата
                                    ALXR То есть, предлагаешь сравнить байт за байтом? А чем плох способ из четвертого поста?

                                    Тем, что Long в VB знаковый и могут возникнуть нюансы.
                                    Впрочем, byte тоже знаковый (кажется) и надо делать дополнительные проверки.
                                      Цитата ALXR @
                                      Впрочем, byte тоже знаковый (кажется) и надо делать дополнительные проверки


                                      ExpandedWrap disabled
                                        ? CBYTE(&HFF)
                                         255
                                        byte беззнаковый
                                          Ну тогда вопрос с проверками отваливается. Код должен работать.
                                            У тебя код лонгов
                                              Цитата ALXR @

                                              Цитата
                                              А чем плох способ из четвертого поста?


                                              Тем, что Long в VB знаковый и могут возникнуть нюансы.

                                              Мне кажется, в коде Akina это учтено... На вскидку, по крайней мере.

                                              Кстати, я таки дорешал:
                                              ExpandedWrap disabled
                                                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


                                              Добавлено
                                              Посмотрите, кому не лень - остались ли здесь какие грабли?
                                                Кстати, код из четвертого поста неверен
                                                  А мой?
                                                    Тьфу ты ну ты, косяк косячный :blush: Записал структуру задом наперед, а потом ещё и думаю: чего это вдруг копировать лонги пришлось шиворот навыворот... хотел даже спросить :)

                                                    Исправляюсь:
                                                    ExpandedWrap disabled
                                                      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
                                                      Цитата ANDLL @
                                                      У тебя код лонгов

                                                      Хм. Хочется извращенцам, которые начинают лезть в дебри на VB, посоветовать переходить на языки другого уровня. Не вижу необходимости использовать язык, предназначенный совершенно для совершенно иных целей, в таких случаях. Аргументирую (для себя) это только ленью авторов программ.
                                                        Такая мелочь, как "получить размер файла" - это дебри?
                                                          Возвращаясь к изначальной задачи - если нужно-таки просто сравнить, не вникая, что там за числа внутри. Тремя ифами я, конечно, не обошелся :blush:
                                                          ExpandedWrap disabled
                                                            'Помним, что раз числа беззнаковые, то отрицательные больше положительных, а самое большое -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
                                                          Можно ли как-то укомпактить эту портянку без потери функционала?

                                                          Добавлено
                                                          Укомпактил так:
                                                          ExpandedWrap disabled
                                                            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
                                                          Сообщение отредактировано: Артур -
                                                            Цитата Артур @
                                                            Такая мелочь, как "получить размер файла" - это дебри?

                                                            Учитывая наличие функции CompareFileTime в WINAPI, структура которой FILETIME полностью идентична структуре LARGE_INTEGER, то все вышеописанное я бы назвал дебрями.
                                                              Учитывая, что такая структура используется не только для размера файла, я бы назвал вышеописанное стандартной ситуацией :)
                                                                Код из сообщения #28? Стандартная ситуация?
                                                                  Раз в языке нет длинных беззнаковых, а нужно, значит достаточно стандартная. Особого напряжения ума и каких-то глубоких изощрённых подходов там, вроде нет - где дебри? Всё понятно и более-менее очевидно.
                                                                    Раз в языке нет длинных беззнаковых чисел, то:
                                                                    1. Они там, скорее всего, не нужны.
                                                                    2. Язык устарел.
                                                                    3. Следствие из 2-го: На нем хорошо учиться программированию и как можно скорее переходить на другой (если в планах есть продолжать).
                                                                      ALXR
                                                                      С этим согласен.
                                                                      Но если есть большой проект, в который вбухано много времени и сил, и который теперь уже практически нереально перевести на другой язык (а другой язык сначала нужно ещё и изучить :blink: ), то надо его всё же доделать в том виде, в каком он уже есть. Такие дела :)
                                                                        Да никто же не спорит. :) Речь о том, что есть одна ф-ция, которая занимается тем, что требуется в теме. Непонятно, зачем изобретать велосипеды. Да еще такие.
                                                                        Каждый сам кузнец своей оградки. :)
                                                                          Цитата ALXR @
                                                                          Речь о том, что есть одна ф-ция, которая занимается тем, что требуется в теме.

                                                                          Какая?
                                                                          1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                                                          0 пользователей:


                                                                          Рейтинг@Mail.ru
                                                                          [ Script execution time: 0,0751 ]   [ 15 queries used ]   [ Generated: 9.07.25, 07:37 GMT ]