Логический оператор, обрабатывающий дроби как FALSE - PullRequest
2 голосов
/ 29 мая 2020

Я получаю неожиданный результат при использовании логических операторов с числами меньше 1. Я думал, что VBA будет рассматривать любое число, кроме нуля, как ИСТИННОЕ, но, похоже, дроби обрабатываются как ЛОЖЬ. Так странно.

Что я неправильно понял.

Я свел это к этим двум строкам кода VBA. Первый возвращает то, что я ожидал, но не второй.

Спасибо, kbrown4600

MsgBox 1 And True   ' returns 1
MsgBox 0.5 And True ' returns 0. Unexpected result

1 Ответ

3 голосов
/ 29 мая 2020

Побитовые операторы не выполняют математику с плавающей запятой, поэтому перед тем, как операнды будут переданы оператору And, происходит неявное преобразование для выполнения побитовой операции.

И поскольку побитовая математика дает 0, тогда это может означать только то, что неявное преобразование просто отсекает десятичную часть.

Нижняя строка, ... не выполняйте побитовые операции с нецелыми числами и избегайте неявных преобразований типов в Общее. В стандартной библиотеке есть несколько явных функций преобразования для этого:

Debug.Print VBA.Conversion.CLng(0.5) And True '<~ explicit conversion

CLng это задокументировано для округления 0.5 до 0, если вам нужно определить, нужно ли чтобы округлить до 0 или до 1, а затем четко указать это:

Debug.Print CInt(0.5 + 0.01) And True '<~ explicit "round 0.5 up to 1"

В любом случае работа с нецелочисленными операндами для побитового оператора не имеет смысла.

Если дробная часть равна точно 0,5, CInt и CLng всегда округляют ее до ближайшего четного числа. Например, 0,5 округления до 0 и 1,5 округления до 2.

Javascript имеет худшие причуды, чем в этих частях, не уверен, насколько справедливым является вызов неявных преобразований типов "странно" .

Я думал, что VBA будет рассматривать любое число, кроме нуля, как ИСТИНА

Это зависит от контекста. -1 равно True, а True - Not False. Это делает True -1 внутренне, вероятно, как 32-битное целое число, поэтому в двоичном виде это может выглядеть так:

11111111 11111111 11111111 11111111

Побитовое, логическое значение True должно иметь это представление , потому что это должно быть представление для False:

00000000 00000000 00000000 00000000

Побитовая логика c требует, чтобы два операнда были одного и того же типа, так что биты означают одно и то же с обеих сторон, иначе побитовая операция - которая должна быть простой и быстрой - должна начать выполнять сложный анализ, чтобы выяснить, на что она смотрит, когда это просто не нужно ... если мы примем этот побитовый лог c работает с целочисленными типами, точка.

Можно сделать MsgBox 42 And 12, вы получите побитовый результат 8:

00000000 00000000 00000000 00101010 ' 42
00000000 00000000 00000000 00001100 ' 12
00000000 00000000 00000000 00001000 '  8 (AND)

Результат оператора And всегда будет побитовым - и результатом - то, что мы называем «логическими операторами», - это просто побитовые операторы, работающие с логическими операндами:

00000000 00000000 00000000 00000000 ' False
11111111 11111111 11111111 11111111 ' True
00000000 00000000 00000000 00000000 ' False (AND)

Но если сами операнды не относятся к целочисленному типу, тогда они получают удовольствие с одним перед оператор может их просмотреть. Вот когда True становится -1, и тогда 0.5 становится 0.

...