public class MathTest {
public interface Operator {
public double operate(double d);
}
public static class SimpleAdd implements Operator {
public double operate(double d) {
return d + 1.0;
}
}
public static class DoubleAdd implements Operator {
public double operate(double d) {
return d + 0.5 + 0.5;
}
}
public static class RoundaboutAdd implements Operator {
public double operate(double d) {
return d + 2.0 - 1.0;
}
}
public static void runABunch(Operator op) {
long start = System.currentTimeMillis();
double d = 0.0;
for (int i = 0; i < 5000000; i++)
d = op.operate(d);
long end = System.currentTimeMillis();
System.out.println("Time: " + (end-start) + " ignore:" + d);
}
public static void main(String[] args) {
Operator ra = new RoundaboutAdd();
runABunch(ra);
runABunch(ra);
Operator sa = new SimpleAdd();
Operator da = new DoubleAdd();
runABunch(sa);
runABunch(da);
}
}
결과는
2개의 double 을 더하는게, 하나의 double 을 더하는거 보다 빠르다.
Time: 47 ignore:5000000.0 <-- RoundaboutAdd
Time: 47 ignore:5000000.0 <-- RoundaboutAdd
Time: 141 ignore:5000000.0 <-- SimpleAdd
Time: 125 ignore:5000000.0 <-- DoubleAdd
왜 그럴까?
자바가 과연 미쳤을까?
요즘 장안의 화제인, Heavy Mach Lite 버전을 사용해봤다.
(물론 난 터치 없다. 빌려서 해봤다)
그런데 1분 정도 사용하다가 버그가 발견되었다.
총알이 계속 나가는 버그이다.
그림에서와 같이 손가락으로 이동하면서 메뉴를 띠운다.
그리고 Resume 을 선택한다.
그 후엔 총알이 계속 나가게 된다. 적당히 좌우로 기울이는데만 집중하면 된다.
결국 하고 싶은 얘기는, 어떤 프로그램에서나 State 관리가 어렵다는 것이다.
위 상황은 메뉴를 띠우는 코드에서는 기존 총알을 stop 시키는 코드가 빠져있을 것이다.
아마 전체 게임 State 와 탱크 의 state 가 별개로 관리되기 때문일 것으로 추측 된다.
쉬운 것 같으면서도, 어려운게 상태관리다. 거의 대부분의 버그가 상태 관리에서 발생한다.
요즘 관심 있게 보는 주제 이기도 하다.
TVTimer Spec
setTime(long time)
Sets when this specification should go off.
For absolute specifications, this is a time in milliseconds since midnight, January 1, 1970 UTC.
For delayed specifications, this is a delay time in milliseconds.
1. absolute
setAbsolute(true)
유틸함수
setAbsoluteTime(long when) = setAbsolute(true), setTime(when), setRepeat(false).
2. delayed
setAbsolute(false);
2-a. repeating
setRepeat(true)
2-a-i. regular
setRegular(true)
2-a-ii. non-regular
setRegular(false);
2-b. non-repeating
setRepeat(false);
setRegular(boolean)
Regular specifications attempt to go off at fixed intervals of time, irrespective of system load or how long it takes to notify the listeners.
Non-regular specifications wait the specified amount of time after all listeners have been called before going off again.
유틸함수
setDelayTime(long delay) = setAbsolute(false), setTime(delay), setRepeat(false);
결국 거의 항상 많이 쓰는 2가지 방식은 아래 3개 밖에 없다.
절대시간에 한번
setAbsoluteTime(long when);
또는 반복일때
setDelayTime(long delay), 한번일때
setDelayTime(long delay)+ setRepeat(true); 반복일때.
별거 아닌거 같은데, 매번 API 를 살펴야 하는 귀찮다. 외우자.
위 논문에서 예제로 나온 에어컨 StateChart는 아래와 같다.
위의 StateChart 을 아래와 같이 구현한다.
class AirCon { // context class
public AriConState state; // collaborator object
public Off offState;
public On onState;
public Cooler coolerState;
public Heater heaterState;
public AirCon() { // constructor
offState = new Off(this);
onState = new On(this);
coolerState = new Cooler(this, onState);
heaterState = new Heater(this, onState);
state = offState; // setting default state
}
public void setState(AirConState st) {
state = st;
state.entry();
}
public void powerBut() {
state.powerBut();
}
public void modeBut() {
state.modeBut();
}
// All action become methods
public void setOn() { ... }
public void setOff() { ... }
...
}
class AirConState { // abstract state class
public AirCon airCon; // context reference
public void entry() {};
public void exit() {};
public void powerBut();
public void modeBut();
}
class Off extends AirConState { // state class
public void powerBut() {
airCon.setOn();
exit();
airCon.setState(airCon.onState);
}
}
class On extends AirConState{ // composite state
private AbsOnState subState;// collborator object
private AbsOnState onHistory;
private int hist = 0;
public void entry() {
if(hist > 0) // implementing history
subState = onHistory;
else {
subState = airCon.coolerState;
hist = 1;
subState.entry();
}
public void exit() {
onHistory = subState;
}
public void powerBut() { // outgoing transition
airCon.setOff();
subState.exit();
exit();
airCon.setState(airCon.offState);
}
// delegating substate events
public void modeBut() {
subState.modeBut();
}
// setting next substate
public void setSub(AbsOnState sub) {
subState = sub;
subState.entry();
}
}
class AbsOnState { // abstract composite state
public AirCon m_context;
public On s_context;
/** Empty declarations for entry(), extit() and all events
methods of subclasses of AbsOnState **/
}
class Cooler extends AbsOnState { // substate
public void modeBut() {
m_context.setHeater();
exit();
s_context.setSub(m_context.heaterState);
}
}
class Heater extends AbsOnSteate {
public void modeBut() {
m_context.setCooler();
exit();
s_context.setSub(m_context.coolerState);
}
}
클래스 다이어그램은 아래와 같다.
전형적인 코드니까 외워는게 기계적으로 적용하면 좋겠다. 예제에 Concurrent State 도 하나 더 추가해서 코드를 만들어 놓으면 더 좋겠다.
손으로클래스 갯수가 좀 많이 나와서 실수하기 딱 좋다. 그렇게 되면 오히려 디버깅이 더 어려워 질지도 모르겠다.
물론 해당 논문에서는 JCode 라는 시스템을 만들어서 소스를 출력한다.
JCode 라는 시스템이 없으면, 저런 StateChart 를 만들고, 소스를 손수 작성하면, 나중에 State 가 하나 추가되거나 변경되면, 수정하게 되면 골치다.
State Chart XML 을 입력으로 넣고, 저런 식으로 나오면 괜찮을 것 같기도 하다.
잼있는 자료구조다..
자료구조에 확율을 도입했다고 보면 된다. (대단하다)
사실 한번 보고 나면 아 나도 만들어볼수 있겠구나 하는 생각까지 드는 자료 구조다.
문제는 수식으로 성능을 표현할수가 없으니 ....
Binary Tree 는 자료 구조시간에 많이들 들어봤을 테니까..
이와 비슷하게 성능을 낸다.
오히려 메모리 사용량은 더 작다.
1990년도에 나온 자료구조라고 한다.
일단 Art of Programming 이란 책에는 나오지 않는다.
책이 나온지가 오래되서 그런지도...
자바 1.5 이상 concurrent 패키지에 보면 ConcurrentSkipListMap 이라고 구현체가 있다.
웃기는게, 인터넷에서 찾을 수 있는 가장 간단한 SkipList 구현체도 (가령 int 만 처리하는)
이보다 더 속도가 나오지 않는다.
그래서 혹시나 하고, backport 를 사용해서 1.3 VM 에서 돌려봐도, 더 빠르다.
그래서 메모리 사용량 까지 대강 확인해보니, 역시 메모리 사용량도 별로 차이가 나지 않는다. 2배정도...(2배가 적은지는 요즘 메모리가 하도 커서...)
근데 TreeMap 이 일반적일때는 더 빠르니....
굳이 쓸 필요는 없다..멀티쓰레드 환경이 아니면..
잼있는건 멀티쓰레드 환경에 짱이라는것다. TreeMap 을 멀티쓰레드에서 쓸려면
TreeMap 전체를 lock 을 걸어야 하나, SkipList 일때는 그렇게 걸 필요가 없다는 거다.
그래서 멀티 쓰레드환경에서 아주 좋은 자료구조다.
근데 RSA 같은건 특허가 있는데, 자료구조는 특허가 없는것인가?
그게 갑자기 궁금해진다.
| Object fields | Example hash code | Comments |
|---|---|---|
| Two ints, each fairly randomly distributed between 0 and a fairly large number2. | x ^ y | XORing two numbers with roughly random distribution results in another number still with roughly random distribution3, but which now depends on the two values. |
| Two objects whose classes already have good hash functions (for example Strings or generally other standard library classes). | x.hashCode() ^ y.hashCode() | If the two classes already have good (randomly distributed) hash code functions, then you can treat the two hash codes as "randomly distributed integers" and XOR them. |
| Two ints that have a biased distribution. | (x * p) ^ y Where p is a prime number4 and/or odd number close to a power of 2, such as 17 or 33. |
Multiplying one of the numbers (or, put another way, shifting plus adding/subtracting from itself) will help to ensure that the "biased" bits of one number interact with the more "random" bits of the other, so that the bias is "ironed out" over more of the bits. |
| enums |
Treat as "biased ints": (x.hashCode() * 17) ^ y.hashCode() |
Enums typically have low values (favour the lower bits), so they should be combined with a multiplication to spread them across a wider bit range of the hash code. |
| Two doubles or floats. |
Wrap the primitive in a Float or Double object then call its hashCode() method. new Float(x).hashCode() ^ new Double(y).hashCode() (new Double(x).hashCode() >> 13) ^ new Double(y).hashCode() |
For efficiency (but the JIT compiler may remove the need) you could directly copy the code from Double.hashCode() or Float.hashCode() directly into your hash function. See the hashCode() method of Point2D for an example of this. Hash codes of floats and doubles, in particular those representing powers of 2 (including negative powers of 2: 1/2, 1/4 etc), typically have more variation in the upper bits than in the lower ones. The HashMap's secondary hash code alleviates this problem somewhat, but it may be worth combining the hash codes by shifting one of them right by several bits so that more variation ends up in the lower bits. |
위에꺼로도 안되면 그냥 String 을 전부 더하고, 캐시를 두어서 오버헤드를 방지
public int hashCode() {
int hc = cachedHashCode;
if (hc == 0) {
String varstr = var1 + var2 + var3;
hc = varstr.hashCode();
}
return hc;
}
넣을땐 좀 늦어도 되는데(add)
소팅은 되야 하고(Comparable)
찾을땐 빨리 찾고 싶고 (Hash, Binary search)
좌우 이동은 빠르고 (RandomAccess)
이런 클래스는? SortedListSet ?
없네... 만들어야겠군..
더블버퍼링 할려면 예전엔 귀찮았던거 같은데
Canvas 아주 좋네
classs XXXXXX extends Canvas {
private BufferStrategy strategy;
private
public XXXXXX() {
...
setIgnoreRepaint(true);
createBufferStrategy(2);
strategy = getBufferStrategy();
....
}
public void xxxx_draw() {
Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
.... (아무거나 그린다)
g.dispose();
strategy.show();
}
}
심플하다....
이올린에 북마크하기