이문제에대해 세련된 접근방법은..

devscott의 이미지

진중하게 당면 문제에 답을 구해 보고자 합니다.

문제 답을 구하는 것보다 문제 해결 방법론에 대해
어떻게 접근하는 것인지 보고 싶습니다.

사실 현업 개발 14년 차에 못만들게 없다 자신 하지만
아직 세련된 프로그래밍을 구사하지 못하는 것같습니다.

문제는 다음과 같습니다.

어떤 마켓 클래스에 영업 시작 시간과 영업 끝시간이 설정되었습니다.
현재 시간으로 이 마켓이 영업중인지 알고싶습니다.

하루는 0 시 00분 부터 23 : 55분까지 되었습니다.

문제는 if else 등으로 난잡하게 하고 싶지 않습니다.
아주 세련된 방법이되 여러 시간설정에도 동작하면 좋겠습니다.

class Market
{
Market ( time openTime, time closeTime )
{
m_openTime = openTime;
m_closeTime = closeTime;
}

bool isOpened ( time thisTime )
{

?????????

return True or False;

}
private:
time m_openTime;
time m_closeTime;
}

Market m( 1:00, 12:00 );

m.isOpend( 3:55 ); // true
m.isOpend( 13:00 ); // false

Market m( 23:00, 12:00 );
m.isOpend( 3:00 ); // true
m.isOpend( 13:00 ); //flase

snowall의 이미지

간략화시키자면 2개의 수 a, b를 정했을 때, 주어진 수 x에 대해 a less than b면 x가 a와 b사이에 있는 경우에 true이고, a larger than b이면 x가 a와 b사이에 있는 경우에 false군요

isOpen(int a, int b, int x){
    return ((a-b)(x-a)(x-b)/abs((a-b)(x-a)(x-b))+1)/2;
}

C에서는 False는 0이고 나머지는 다 True라고 하네요. True=1로 하지 않으면 2로 나눌 필요도 없긴 합니다.

a=b, a=x, b=x인 경우에 오동작하는데, 그 부분에 대해서는 문제에서도 예외처리 방법이 없어서 그냥 둡니다.

3:00에 가게를 여는데 3:00을 입력하면 연걸까요 안연걸까요...-_-;;

피할 수 있을때 즐겨라! http://melotopia.net/b

devscott의 이미지

제수준에서 이해하기엔 조금 어렵지만 짧고 간결하네요.

적용해 봤는데 말씀하신거처럼 a, b, x 가 같을때 예외 처리해주었구요..

문제가.. isOpen ( 3, 4, 3 ) 일때 divide zero exception이 발생하구요
이것을 예외처리했더니 x = 3 에대해선 skip하고 4시에 close 되서 이부분에대해 보완이 필요해보입니다.

도와주셔서 감사 드립니다.

snowall의 이미지

isOpen(double a, double b, double x){
    d = 0.00000000001 // double의 최소단위를 넣으면 됩니다.
    return (int((a-b+d)(x-a+d)(x-b+d)/abs((a-b+d)(x-a+d)(x-b+d))+1)/2;
}

좀 무식하긴 하지만 이런식?으로 해결하면 어떨까요?

d의 부호를 +나 -로 바꾸면 open과 close의 경계 시간에서 조금 다른 결과가 나오게 됩니다.

피할 수 있을때 즐겨라! http://melotopia.net/b

yhsuk의 이미지

생각이 좀 필요하네요.

한줄로 해야 한다는 제약이 있는건 아니죠 ^^?
time 자료형이 추상적으로 표현되서 한계값에 대해서 추정하기 힘들고
어차피 if가 들어간 것이긴 한데
아래와 같은 표현 정도면 이해하기 쉽지 않을까요?

class Market
{
    Market ( time openTime, time closeTime )
    {
        m_openTime = openTime;
        m_closeTime = closeTime;
    }
 
    bool isOpened ( time thisTime )
    {
        time openTime = m_openTime;
        time closeTime = m_closeTime;
        time queryTime = thisTime;
 
        if (m_openTime > m_closeTime) closeTime += 24:00;
        if (m_openTime > queryTime) queryTime += 24:00;
 
        return (openTime <= queryTime) && (queryTime <= closeTime);
    }
 
private:
    time m_openTime;
    time m_closeTime;
}

Signature :) - "여유를 갖고 행동하되 게을러지지 말자"

devscott의 이미지

잘 작동 할것 같습니다.
다만 time 변수가 24:00 간 밖에 못 담고 24를 증하가면 day 변수가 증가 필요하겠네요.
물론 시간을 int로 고쳐서 사용하면 잘되는것 같습니다.

도와주셔서 감사합니다.

lovian의 이미지

시작 시간, 종료 시간을 time_t 변경하여 가지고 있고,
입력 받은 값을 time_t로 변경하여

입력 값이 시작, 종료 사이에 있으면 영업중.

이런건 어떨까요?
굳이 코드는 필요 없을 것 같아서 생략합니다. :)

-----------------
한글을 사랑합니다.

semmal의 이미지

class Market
{
	Market ( time openTime, time closeTime )
	{
		m_openTime = openTime;
		m_closeTime = closeTime;
	}
 
	bool isOpened ( thistime thisTime )
	{
		return openTime <= thisTime && thisTime <= closeTime;
	}
 
private:
	time m_openTime;
	time m_closeTime;
}

time과 thistime에서 <= 연산자만 재정의하면 되지않을까요?

또는,

class Market
{
	Market ( time openTime, time closeTime )
	{
		m_openTime = openTime;
		m_closeTime = closeTime;
	}
 
	bool isOpened ( time thisTime )
	{
		bool b = openTime <= thisTime && thisTime <= closeTime;
		return !(b ^ (openTime <= closeTime));
	}
 
private:
	time m_openTime;
	time m_closeTime;
}

XOR가 갑자기 헷갈리네요. 같을 때 0이 맞군요.

------------------------------
How many legs does a dog have?

devscott의 이미지

헛갈리네요..

o: 1 c : 2 t : 3

!( false ^ ( true ) ) = false . ... okay

o: 2 c : 1 t : 3

!( false ^ ( false ) ) = true ... okay

o: 1 c : 3 t : 2
!( true ^ ( true ) ) = flase ... NG

이렇게 되는거 맞나요?

planetarium의 이미지

if (m_openTime < m_closeTime)
        return m_openTime < thisTime && thisTime < m_closeTime;
else
        return m_openTime < thisTime || thisTime < m_closeTime;

그냥 이정도면 깔끔하고 보기 좋지 않나요...;;
devscott의 이미지


open 3, close 1 this 3
에서 문제가 되네요.

그래서
else
return open <= thisTime || thisTime < closeTime;

로 고쳐서 했는데

open 2, close 1, this 1 에서 true 가 되네요..

도와주셔서 감사합니다.

planetarium의 이미지

음? 말씀하신대로 고치고 나면 open 2, close 1, this 1에서 false 가 되는것 같은데요...
첫 댓글과 마찬가지로 저도 "open순간에, close 순간에 열려있는건가?" 고민했는데
[open, close) 형태가 되나보네요.

그럼

if (m_openTime < m_closeTime)
        return m_openTime <= thisTime && thisTime < m_closeTime;
else
        return m_openTime <= thisTime || thisTime < m_closeTime;

이 코드에서 어디가 문제가 될까요...?
fairly의 이미지

00:00~23 : 55
에서 유효숫자는 0~23입니다.
단 오픈과 클로즈는 시간단위라고 가정합니다.

byte 표현가능하겠죠. 의사코드를 만들어보면

byte hour[24];
 
Market( time openHour, time closeHour )
{
   clear(hour);
   for(idx = openHour; idx <= closeHour; idx++) {
     hour[idx]= true;
   }
}
 
bool isOpened ( time thisHour )
{
    return hour[thisHour]; // !!caution :buffer overflow check 
}

devscott의 이미지


속도가 엄청 빠르겠군요...

근데 openHour = 17 로 하고 closeHour 7 시로 하면 배열 범주를 벚어나버리겠네요.
간단하게 map table 을 채울수 있다면 좋겠습니다.

좋은 내용감사드려요.

planetarium의 이미지

for(idx = openHour; idx < closeHour; idx=(idx+1)%24) {

요래 하면 되네요, 보긴 좀 안좋아져도
익명 사용자의 이미지

원칙을 바꾸면 어떨까요?

굳이 사람이 생각하는 방식으로 맞추지 말고 말입니다.

class Marker {
    Marker(time open_from, time open_range) {
        ....
    }
    bool isOpend(time when) {
        return this.open_From >= when && this.open_from + this.open_range < when
    }
};

하루를 24시간으로 굳이 생각할 필요는 없지 않습니까. ^^

snowall의 이미지

20시부터 그 다음날 3시까지가 영업시간인 경우에, 12시에 대해 물어보면 어떻게 되나요?

피할 수 있을때 즐겨라! http://melotopia.net/b

snowall의 이미지

begin, end, x는 모두 0~n까지의 정수라고 가정합니다. 하루 단위는 어차피 초나 밀리초 단위의 정수로 떨어질테니 그렇다 치죠 뭐.

isOpen(int begin, int end, int x){
    return (x-begin+n)%n<(end-begin+n)%n;
}

이렇게 하면 잘 작동할 것 같네요.

속도 향상 요소라면, n-begin과 (end-begin+n)%n은 미리 계산해놔도 된다는 점?

planetarium님과 위에 익명님의 의견에서 아이디어를 떠올렸습니다

피할 수 있을때 즐겨라! http://melotopia.net/b

snowall의 이미지

다시 생각해보니 나눗셈도 필요가 없네요

isOpen(int a, int b, int x){
    return (a-b)(x-a)(x-b)>0;
}

이렇게 만들면 원하는 조건을 모두 만족하는 것 같습니다.

부등호를 >을 쓸건지 >=을 쓸건지는 좀 더 생각해봐야겠지만요

피할 수 있을때 즐겨라! http://melotopia.net/b

익명 사용자의 이미지

지금까지 나온 답 중에선 이게 제일 멋지네요.

익명 사용자의 이미지

a를 시작시간, b를 끝시간, t를 현재시간이라고 합시다.
a,b,t를 편의상 음이 아닌 정수라고 합시다.
그러면 요청하신 것을 위한 조건 세가지는 다음과 같은 세 명제함수로 표현 가능합니다.

p: a q: t r: a

가능한 조합을 진리표로 그려보면 다음과 같습니다.
p q r
0 0 0
0 1 0
1 0 0
1 1 0
0 0 0
0 1 0
1 0 0
1 1 0

여기서 님이 요구하는 명제함수는 pqr이 111, 010, 100일 때만 참인 함수입니다.
(a,b와 t의 관계를 생각해보시면 됩니다)
이런 명제함수는 찾아내기 매우 어렵고 찾아낸다 하더라도 식이 복잡하므로 if문을 사용함만 못합니다.

그러나 천만 다행히도, pqr이 001 혹은 110인 경우는 없습니다.
따라서 이 두가지 경우에 대해서는 결과값이 참이던 거짓이던 상관없습니다.
어차피 그런 경우는 없으니까요.

여기까지 온 다음에 진리표를 다시 그리고 뚫어지게 쳐다보다 보면 우리는 xor을 떠올릴 수 있습니다.
두 수가 같으면 거짓이고 다르면 참인 논리연산자 입니다.
p와 q를 xor로 묶으면, 뭔가 될 것 같죠?
약간의 노가다를 거치면, 이제 다음과 같은 식을 얻습니다. 이게 님이 원하는 명제함수입니다.

(p XOR q) XOR (NOT r)

이걸 C로 쓰면 다음과 같습니다

return ((a < t) ^ (t < b)) ^ (a > b);

잘 작동하는지 확인은 귀찮으므로 다른분께 맡깁니다^^
망신 안당하길... 망신 안당하길...

익명 사용자의 이미지

bb코드 때문인가요?
다시 올립니다.

a를 시작시간, b를 끝시간, t를 현재시간이라고 합시다.
a,b,t를 편의상 음이 아닌 정수라고 합시다.
그러면 요청하신 것을 위한 조건 세가지는 다음과 같은 세 명제함수로 표현 가능합니다.
 
p: a<t
q: t<b
r: a<b
 
가능한 조합을 진리표로 그려보면 다음과 같습니다.
p q r
0 0 0
0 1 0
1 0 0
1 1 0
0 0 0
0 1 0
1 0 0
1 1 0
 
여기서 님이 요구하는 명제함수는 pqr이 111, 010, 100일 때만 참인 함수입니다.
(a,b와 t의 관계를 생각해보시면 됩니다)
이런 명제함수는 찾아내기 매우 어렵고 찾아낸다 하더라도 식이 복잡하므로 if문을 사용함만 못합니다.
 
그러나 천만 다행히도, pqr이 001 혹은 110인 경우는 없습니다.
따라서 이 두가지 경우에 대해서는 결과값이 참이던 거짓이던 상관없습니다.
어차피 그런 경우는 없으니까요.
 
여기까지 온 다음에 진리표를 다시 그리고 뚫어지게 쳐다보다 보면 우리는 xor을 떠올릴 수 있습니다.
두 수가 같으면 거짓이고 다르면 참인 논리연산자 입니다.
p와 q를 xor로 묶으면, 뭔가 될 것 같죠?
약간의 노가다를 거치면, 이제 다음과 같은 식을 얻습니다. 이게 님이 원하는 명제함수입니다.
 
(p XOR q) XOR (NOT r)
 
이걸 C로 쓰면 다음과 같습니다
 
return ((a < t) ^ (t < b)) ^ (a > b);
 
잘 작동하는지 확인은 귀찮으므로 다른분께 맡깁니다^^
망신 안당하길... 망신 안당하길...
익명 사용자의 이미지

진리표 부분에서 약간의 오류가 있는데... r이 0인 경우와 1인 경우 둘다 있어야 합니다.
p q r
0 0 0
0 1 0
1 0 0
1 1 0
0 0 1
0 1 1
1 0 1
1 1 1

익명 사용자의 이미지

써놓고 보니까 semmal님 두번째 답이랑 같네요
김이 팍 샜습니다

익명 사용자의 이미지

다시 정오표.
 
(p XOR q) XOR r
return ((a < t) ^ (t < b)) ^ (a < b);
 
위 함수의 진리표. 진리함수는 X
p q r X 
0 0 0 0 거짓 b<=t<=a
0 1 0 1 참 t<b<=a
1 0 0 1 참 b<=a<t
1 1 0 0 없음
0 0 1 1 없음
0 1 1 0 거짓 t<=a<b
1 0 1 0 거짓 a<b<=t
1 1 1 1 참 a<t<b
 
한번 꼬이니까 걷잡을수가 없네요 헉헉
여러번 검토했으니까 아마 맞을겁니다.