[Ihoo] 연산자에 대해 알아봅시다.
페이지 정보
작성자 Leona123 작성일 24-10-03 17:16 조회 560 댓글 0본문
먼저 연산부호들에 대해 간단히 설명하겠습니다. 원본파일은 DOCS폴더의 EXP.TXT입니다.
써보지 않은것이나 모르는 것은 원문그대로 놔뒀고 여기선 간단하게 설명했으니 원본파일을
한번쯤 보시는것도 괜찮을 듯 합니다.
====================================================================
1. 무겐에선 CNS파일과 CMD파일에서 명령어와 트리거를 쓸 때 연산자를 쓸수 있습니다.
값은 정수와 실수가 있는데 소숫점이 있는 값인 실수는 소숫점 아래 6자리까지 표현가능합
니다.
====================================================================
정수 : -1 0 1 2 같은 수
실수 : -0.24 12.45 4.543745 같은 수
====================================================================
2. 산술연산부호 : 학교에서 수학배운 사람이면 다 압니다.
====================================================================
+
더하기
-
빼기 또는 음수를 나타냄
*
곱하기
/
나누기
컴퓨터 언어를 배우신 분이라면 아시겠지만 나누기 연산을 할 때 정수끼리 연산을 하면 결
과도 정수로 나옵니다. 실수값을 얻고 싶으시면 둘중하나는 실수로 써야 합니다.
예) 7/2 = 3 7.0/2.0 = 3.5 7/2.0 = 3.5
%
나눈 후의 나머지를 구하는 연산자입니다. 실수값에 쓰면 에러납니다. 예) 7%2 = 1
**
The exponentiation operator. If x and y are both ints >= 0, then x**y
gives an int representing x raised to the power of y (we define 0**0 =
1). Otherwise, x**y is computed as an exponentiation of real numbers
(converting x and y to floats first if necessary). The result of an
invalid exponentiation such as -1^.5 will be discussed in the section on SC values.
!
NOT을 나타내는 부호.
!x 라고 쓰면 x값이 0이 아니면 0(false)이 되고 x값이 0이면 1(true)이 됩니다.
트리거에도 !selfanimexist(xxx)(애니매이션xxx이 존재하지 않을때) 식으로 쓰이죠.
&&
논리적 AND 부호.
x && y 라고 썼을 때 x랑 y가 둘다 0이 아닐 경우 1(true)값을 반환하고 그렇지 않을
경우 0(false)을 반환합니다.
트리거에 쓸 때
trigger1 = (조건1)
trigger1 = (조건2)
이것을
trigger1 = (조건1) && (조건2)
으로 단축해서 쓸수 있습니다. 조건1과 2를 모두 만족할 때 라는 뜻이 되죠
||
논리적 OR 부호
x || y 라고 썼을 때 둘중 하나이상이 0이 아니면 1(true)값을 반환하고 둘다 0이면 0을
반환합니다. &&처럼 트리거에도 쓰임
^^
논리적 XOR부호
x ^^ y 라고 썼을 때 둘중 하나만이 0이 아닐 경우 1(true)을 반환, 그렇지 않으면 0을 반환
합니다. 둘다 0이 아닐지라도 0(false)을 돌려줍니다.
~
The bitwise NOT operator. ~x inverts the bits of x's binary (two's
complement) representation. It is an error to apply this to a float --
for the result of such an operation, see the section on SC values.
&
The bitwise AND operator. The nth bit of x&y is set if and only if the
nth bits of both x and y are set. Returns an SC value if either of x or y is a float.
|
The bitwise OR operator. The nth bit of x|y is set if and only if the
nth bit of either x or of y (or both) is set. Returns an SC value if either of x or y is a
float.
^
The bitwise XOR operator. The nth bit of x^y is set if and only if the
nth bit of exactly one of x and y is set. Returns a SC value if either of x or y is a
float.
=
같다는 뜻을 나타내는 부호
:=
The assignment operator. An unredirected variable name (var(n) or fvar(n) for suitable
values of n) must appear on the left-hand side. If the left-hand side contains an integer
variable, then the right-hand side is truncated to an integer before assignment. If the
left-hand side contains a float variable, then the right-hand side is converted to float if
necessary before assignment. In both cases, the value of the expression is the value that
is assigned to the variable.
오른쪽의 값을 왼쪽에다 지정시켜줄수 있습니다? 사용예는 이 문서 끝에서 2번째 페이지
참조.
!=
틀리다(아니다)는 뜻을 나타내는 부호. 역시 트리거에도 쓰임
<
작다는 뜻을 나타내는 부호죠. x < y 라고 하면 x가 y보다 작을 때 라는 뜻이 됩니다.
<=
작거나 같다는 뜻을 나타내는 부호
>
크다는 뜻을 나타내는 부호
>=
크거나 같다는 뜻을 나타내는 부호.
(<= , >=는 =< , => 로 쓰면 에러가 납니다. 꼭 <= 나 >= 로만 써야 합니다.)
=[,]
!=[,]
=[,)
!=[,)
=(,]
!=(,]
=(,)
!=(,)
범위를 나타내는 것들입니다.
예를 들어 x = [1,5] 라고 하면 x값이 1,2,3,4,5중에 하나일 때 라는 것이고
x = (1,5) 라고 하면 x값이 2,3,4 중에 하나일 때 라는게 됩니다.
마찬가지로 x = [1,5) 는 x값이 1,2,3,4 중에 하나일 때
x = (1,5] 는 x값이 2,3,4,5 중에 하나일 때 라는게 됩니다.
앞에 !가 붙게되면 반대의 경우를 나타냅니다. x != [1,5]라고 하면 x값이 1,2,3,4,5 가 아닐
때 란 뜻이 됩니다.
트리거에 쓸 경우 || 나 && 부호를 한줄에 같이 쓸땐 괄호를 쳐야 하는데 예를들어.
trigger1 = var(1) = [0,5] || time = 0 이런식으로 하면 에러가 납니다.
trigger1 = (var(1) = [0,5]) || time = 0 이런식으로 써야합니다.
====================================================================
3. 연산 순서
====================================================================
여러 부호들이 섞여있을 때 계산 순서는 다음과 같습니다.
! ~ - (Unary operators:단일 부호)
**
* / %
+ -
> >= < <=
= != intervals
:=
&
^
|
&&
^^
||
같은 레벨의 부호가 있을 경우 왼쪽에서 오른쪽으로 하며 괄호()를 칠 경우 괄호안의 것부
터 먼저 계산합니다. 컴퓨터 프로그래밍 언어의 하나인 C언어랑 같다고 하네요.
괄호를 여러개 쓸 경우 수학처럼 중괄호같은걸 쓰는게 아니라 그냥 괄호를 여러개 칩니다.
예)
3+2*5 = 13 , (3+2)*5 = 25, (6-(3+2))*5 = 5
5.0*5/6 = 25.0/6 = 4.166667
-!0 = -(!0) = -(1) = -1
CNS나 CMD를 짤 때 원하는결과가 나오지 않으면 계산 순서를 한번 잘 보도록 합시다.
====================================================================
4. Expression syntax : 표현 구문론(?) 원문 놔둠.
====================================================================
Basically, any normal arithmetic expression is allowable. In addition,
since the relational operators (>, <=, etc.) are viewed as returning
ints, it is possible to operate on their return values, giving some
unusual-looking expressions like
1.0 = (2 = (1 > 0) + !(0 < 1))
근데 이 문장에서 (0 < 1)은 틀린것같죠? 아마 일렉바이트에서 잘못쓴것같네요. (0 > 1)로
바꿔야 다음과 같은 진행이 될수 있지요.
The 1 > 0 term evaluates to 1, and the 0 < 1 term evaluates to 0.
Hence
!(0 < 1) evaluates to 1, so the expression simplifies to
조건을 만족할 경우 1을 돌려주며 그렇지 않을 경우 0을 돌려준다고 했으니 이 문장은 다음
과 같이 됩니다.
1.0 = (2 = 1 + 1)
Since 2 = 1 + 1, the term in parentheses evaluates to 1, so the
expression further simplifies (after type conversion) to
결국 다음과 같이 됩니다.
1.0 = 1.0
which evaluates to 1 (int), since the equality holds.
A notable restriction in expression syntax is that interval operators
are only allowed to appear on the rightmost side of an expression. If
part of an expression is enclosed in parentheses, then that part is
considered a subexpression, and an interval is allowed to appear on the
right side of that subexpression. So the following is a well-formed
expression, which evaluates to 0:
(1 = [0,2]) = (0,1)
But the following is not well-formed:
(0,1)은 무조건 만족할수 없는 조건이기 때문에 좋지 않다 라고 하네요.
1 = [0,2] = (0,1)
In addition, no operator symbols other than = or != may appear before an interval. So
an expression like 5 > [0,2], or 4 + [1,4), is not allowed.
마찬가지로 4 + [1,4) 같은건 말도 안되니 쓰지 말라는군요.
In comma-separated parameter lists, such as the arguments to some
function-type triggers or parameters to state controllers, each expression in the list is
considered a separate subexpression, and therefore intervals may appear at the end of
those subexpressions.
====================================================================
5. 트리거들 (원문을 지우려다가 그냥 놔뒀습니다.)
====================================================================
For historical reasons, two distinct constructs are both called
"triggers." The first is what might be more properly called a
condition-type trigger, and the second is what might be more properly
called a function-type trigger. For instance, in the CNS, a typical
state controller might look like
[State 1234, 5]
type = ChangeState
trigger1 = time = 0
value = 0
(스텟 시작하자마다 스텟 0으로 가라 라는 것이군요)
The entire line "trigger1 = time = 0" is a condition-type trigger. If
the expression "time = 0" evaluates to a nonzero value, then the
ChangeState controller is executed. If the expression "time = 0"
evaluates to zero, then the ChangeState controller is not executed.
Thus whether the condition is zero or nonzero affects whether the
controller is triggered.
On the other hand, the word "time" appearing in the expression is a
function-type trigger. It returns a value, namely, the amount of time
that the player has been in state 1234. Note that a function-type
trigger doesn't "trigger" anything. It just gives a value that can be
acted on within the expression.
To further illustrate the difference, let us consider a different state controller:
[State 1234, 5]
type = VarSet
trigger1 = 1
v = 0
value = time + 5
var(0)을 time + 5로 설정하라 는 것입니다. trigger = 1로 돼있으면 스텟 내내 실행됩니다
이런식으로도 쓸 수 있다. 라는 것 같네요. 다음과 같이 써도 위와 같습니다.
[State 1234, 5]
type = VarSet
trigger1 = 1
var(0) = time + 5
Note that the condition-type trigger "trigger1 = 1" now contains no
function-type triggers within it. Since the expression "1" always
evaluates to 1, the controller will be triggered every frame. To
determine what value to assign var0, the expression "time + 5" is
evaluated. The function-type trigger "time" returns the player's
statetime. Then 5 is added and the result is stored in var0.
A complete list of function-type triggers can be found in trigger.doc.
In general, which of the two types of triggers is meant is clear from
context. Where there is some ambiguity, the terms "condition-type
trigger" and "function-type trigger" will be used.
====================================================================
6. Trigger redirection
====================================================================
이 부분은 trigger.txt에 포함되어있는게 나을것같아서 09-트리거 에 옮겼습니다.
====================================================================
7. SC values : 원문그대로
====================================================================
There are several sources of unrecoverable error in expressions. For
instance, one could attempt to divide by 0, evaluate the square root of a negative
number, or attempt to redirect a trigger to a nonexistent destination. In these situations,
SC values are used as a way to complete expression evaluation gracefully.
An SC value is a special kind of int which can only take on the values 1 or 0, called
SC true (STrue) and SC false (SFalse). The result of any operation or trigger
evaluation on an SC value is that SC value. (In other words, you can think of the SC
values as variants on the "bottom" element in computation theory. Semantically
speaking, CNS expression evaluation is strict in bottom.) If two SC values are given to
the same operator, then the leftmost one takes priority.
For instance, the expression
4 + (1/0)*2
evaluates to 4 + (SFalse) * 2, which evaluates to 4 + SFalse, which
evaluates to SFalse. On the other hand,
STrue / SFalse
would evaluate to STrue, because STrue comes on the left. Finally,
helper, time
would evaluate to SFalse if called with no helpers.
Currently, STrue is unused. Only SFalse is returned in error conditions. This means
that any condition-type trigger that causes an error during evaluation will not trigger.
So, in
type = ChangeState
trigger1 = helper, statetype = A
value = 0
the ChangeState controller would never be executed if no helpers
existed, because the expression "helper, statetype = A" would evaluate
to SFalse, which is 0.
The documentation on function-type triggers explains exactly when those
triggers will return SFalse.
SC values were originally called short-circuit values, because evaluation on an SC value
"short-circuits" and does not act as normal. However, this nomenclature had the
potential to cause confusion with short-circuit logical evaluation, so it had to be
changed, though not so drastically as to cause further confusion. Hence short-circuit
values became SC values. At the moment, SC officially stands for "skip and carry",
because when an SC value is encountered, normal calculation is skipped and the SC
value is simply carried on. Other possibilities for SC include "semantic codomain" and
"so-called". We welcome better suggestions for what SC should stand for.
====================================================================
8. More on function-type triggers : 원문그대로
====================================================================
Most function-type triggers either take no arguments or take arguments
in a parameter list. For instance, the time trigger takes no arguments, whereas the
ifelse trigger takes three arguments
ifelse(exp1,exp2,exp3)
where exp1, exp2, and exp3 are all valid expressions. In this kind of
situation, exp1, exp2, and exp3 are all considered separate subexpressions, so intervals
can appear on the rightmost end of each of those subexpressions. The order of
evaluation of parameter lists is from left to right.
Due to irregular syntax, some old function-type triggers cannot take
expressions as their arguments. Because of this, they cannot be
integrated into expressions in the standard manner. For nonstandard
triggers of this type, the triggers can only appear with certain sets of operators and
arguments (which are outlined in trigger.doc). In
particular, these triggers cannot take expressions as their arguments. For instance,
trigger1 = AnimElem = (1+1)
is an invalid expression.
틀린 문장이라네요
Old-style function-type triggers appear only in "clauses" (trigger, relational operator,
argument). These clauses are treated as a single unit (specifically, a single nullary
trigger) for the purposes of expression evaluation. This means, among other things, that
the concept of operator precedence is not applicable to operators appearing within an
old-style function-type trigger clause. For instance, in
trigger1 = AnimElem = 5 + 4
the expression is broken down into three units:
{AnimElem=5} {+} {4}
The "AnimElem=5" unit is treated as the name of a nullary trigger, hence the +
operator does not have precedence over the = appearing within the name "AnimElem=5".
In other words, this expression means something like "Execute the trigger called
`AnimElem=5', then add 4 to the result."
The list of old-style function-type triggers, and expression-capable replacements if
applicable, is as follows:
AnimElem, superseded by AnimElemTime
P1Name, P2Name, P3Name, P4Name
StateType, P2StateType
Command
MoveType, P2MoveType
TimeMod, superseded by the % operator
ProjHit, ProjContact, ProjGuarded; superseded by ProjHitTime,
ProjContactTime, and ProjGuardedTime
====================================================================
9. Expressions in state and state controller parameters : 원문그대로
====================================================================
For the most part, any parameter to the statedef or a state controller
can be an expression. The exceptions are parameters that are given as
strings. For instance, hit attributes, guardflags, etc. cannot be
specified as expressions. Also, the ForceFeedback controller, as well as the
ignorehitpause and persistent parameters to all controllers, are irregular in that they
cannot take expressions.
State controller parameters are evaluated at the time the controller is triggered, and are
not subsequently re-evaluated unless the controller is triggered again. Parameters that
are given as comma-separated lists are evaluated from left to right. To achieve
continual evaluation of controller parameters, the controller must be continually triggered.
In the case of certain controllers such as HitDef, it is not always wise to use continual
triggering, since this decreases performance and also may lead to undesired behavior. In
this case, the programmer may wish to try to delay triggering the HitDef as long as
possible, so as to evaluate the HitDef parameters right before they are used.
====================================================================
10. 속도최적화(저사양 컴을 위한 소스의 속도 최적화입니다. 원문은 지우지 않고
놔뒀습니다. 고사양 컴이라도 속도최적화를 하면 cpu점유율을 낮출수 있죠)
====================================================================
MUGEN evaluates condition-type triggers for a state controller in the following order:
First it evaluates triggeralls, from top to bottom. If any of the triggeralls evaluates to 0,
the rest of the triggers are skipped and evaluation proceeds to the next controller. If all
the triggeralls evaluate to nonzero, then the engine starts to evaluate trigger1's, from
top to bottom. If any of these evaluate to 0, then evaluation skips to the first trigger2,
and so on. If all the triggers in a block (besides triggerall) evaluate to nonzero, then the
state controller parameters are evaluated and the controller is triggered.
In other words, the logical evaluation of triggers is short-circuited.
In C-like notation, this setup might be denoted
triggerall,1 && triggerall,2 && ... && ((trigger1,1 && trigger1,2
&& ...) || (trigger2,1 && trigger2,2 && ...) || ... )
where (e.g.) trigger1,2 denotes the second trigger1 line, trigger2,1 denotes the first
trigger2 line, etc. The logical evaluation of this trigger group would then be
short-circuited as in C.
Because of this system, considerable performance gains can be attained by organizing
expressions so that the condition-type triggers are as simple, and as few in number, as
possible. The bulk of the "work" can be offloaded to the state controller parameters,
which are only evaluated once at trigger time, instead of every frame that the player is
in the state. For instance,
[State -1]
type = ChangeState
trigger1 = command = "a"
trigger1 = power < 1000
value = 3000
[State -1]
type = ChangeState
trigger1 = command = "a"
trigger1 = power >= 1000
value = 3001
[State -1]
type = ChangeState
trigger1 = command = "a"
trigger1 = power >= 2000
value = 3002
위의 세 명령어들을 다음과 같이 쓰면 뜻은 같으나 처리 속도가 향상됩니다.
[State -1]
type = ChangeState
trigger1 = command = "a"
value = 3000 + (power >= 1000) + (power >= 2000)
Further speedups are possible if triggeralls that are most likely to be false are placed
highest in the triggerall block. Similarly, the trigger1 block should be the most likely
block to trigger, but within the trigger1 block itself, the triggers that are most likely to
evaluate to 0 should be placed highest. For state controllers with many triggers
containing duplicated conditions, it may be faster to break the controllers up into two
separate blocks, each with its own set of triggeralls.
If you have a complex condition which is being used as the trigger condition for many
consecutive state controllers, you may wish to save the value of the condition in a
variable, then use that variable as a trigger to the subsequent controllers. For instance,
trigger1 = (command="abc" && command!="holddown" && power>=1000) ||
(command="abc" && command!="holddown" && var(5)) ||
((command != "abc" || command = "holddown") && power>=2000)
이것을 다음과 같이 써서 속도를 향상시킬수 있습니다.(var(0)이 사용가능하다고 쳤을때)
trigger1 = (var(0):=(command="abc" && command !="holddown") && power>=
1000) || (var(0) && var(5)) || (!var(0) && power>=2000)
중복해서 사용할 긴 문장을 :=를 이용해 var(0)로 지정해주고 2,3번째 쓸땐 그냥 var(0)으로
대체해버렸습니다. 그러니까 밑 키를 누르지 않은 상태에서 abc 커맨드를 입력할 경우 조건
을 만족하므로 var(0) = 1이 되고 그렇지않을 경우는 var(0) = 0이 돼서 뒤의 문장에서도
똑같이 작용하는 것입니다.
Finally, since the expression parser performs no optimization on expressions, an
expression like
trigger1 = ctrl
이렇게 쓰면 밑의 문장과 뜻은 같지만 처리속도가 빠릅니다.
trigger1 = ctrl = 1
댓글목록 0
등록된 댓글이 없습니다.