pascal 은 기본적으로 1부터 시작하고 있고, 배열 인덱스를 재배치 할 수도 있다 (시작을 음수로도 지정 가능)
C의 포인터를 이용하면 역시 음수 index를 사용할 수는 있지.
ex)
#define RADIUS 1000
#define RAD2DIA_DREG 1
#define DIAMETER (RADIUS * 2 + RAD2DIA_DREG)
int pixelsInSin[DIAMETER];
int* centerInPixels = pixelsInSin + RADIUS;
위의 예는 픽셀의 단위에서 중앙이 픽셀과 픽셀 사이에 위치하는 애매함을 해결하기 위해
지름이 반지름 * 2 + 1 이 되는 아름답지 않은 상황을 반영한 것.
이 코드에서 우리는 centerInPixels[-RADIUS] 부터 centerInPixels[RADIUS] 까지 접근 할 수 있다.
sin, cos 같은류의 -1 ~ +1 범위 연산을 수행하기 적합한 코드지.
자연수의 정의는 0을 포함하기도 하고(집합론) 포함하지 않기도 한다.
집합론에서 0의 정의는 null 이고, (의미적으로 nothing 이 아니다. no something 이다. 우주는 무의 공간이 아니거든)
1의 정의는 {null} // something
인데 반해
2의 정의는 {{null}, {null}} 또는 (수론으로 연결됨)
{null, {null}} (집합론, 경우의 수를 센 정보량적 표현)
로 표현되는 것과 같은 이치다.
이런 문제는 min to max 의 범위 문제로 이어지는데,
정규화 시킨 0 ~ 1 의 범위가 scaling 과 같은 transform 에 가장 아름답지만,
주기성의 out of bound 를 clamp 할 수 있는 나머지 연산(%) 은 range - 1 의 결과를 얻기에
rand() 류의 함수 역시 범위 - 1 의 max 를 갖는다.
조금 말이 어렵지?
우리는 우리의 문제와 해결방법을 다양한 용도에 사용될 수 있게 하기 위해 정규화를 해야한다.
가령 20~50 범위의 입력을 10 ~ 100 범위의 출력으로 바꾸고 싶다는 것 과같은 transform 을 자주 구현하게 되는데
이럴 때, 네 가지 일반적 단계를 거치게 된다.
1. min을 0점으로 이동 (min의 normalize)
2. max를 1로 바꿈 (max의 normalize)
3. 스케일링 (size 의 reflection)
4. 결과점(원점)으로 이동 (position 의 reflection)
위의 단계대로 20~50 을 10~100 으로 바꾸어 보면
1. 입력 - 20 을 해서 0~30 범위를 얻는다
2. 30으로 나누어 0~1 범위를 얻는다
3. 90으로 곱하여 0~90 범위를 얻는다
4. +10 해서 10~100 범위를 얻는다
로 전개 되는 것이다.
이 예는 특별한게 아니다.
RGB 의 각 색상 콤포넌트의 범위를 0~255 로 정의하는 시스템도 있고 0~1로 정의하는 시스템도 있다.
0~1로 정규화해서 표현하지 않고 MAX를 0.9 나 0.99 0.999 로 표현한다면 얼마나 바보같을지 생각해 봐라. 우습지만 그런 시스템 흔하다.
만약 누군가 0~255 의 RGB 색상 공간을 0~65535 의 sRGB 색상공간이나 0~15 의 색상공간으로 변환하는 일을 빈번하게 수행한다고 가정하자.
정규화를 하지 않으면 변환 전의 format 을 사용해 나올 수 있는 경우의 수를 모두 구현해야 한다.
outputComponent = inputComponent / inputMax * outputMax
하지만 입력(inputComponent)을 0~1로 변환한 다음이라면,
outputComponent = inputComponent * outputMax
이렇게 간단히 outputMax의 곱셈만 수행하면 되고 변환 전의 format 을 기억할 필요가 없다.
여기서 내가 말하고자 하는것은 한가지다.
min을 1로 하여 자연수 max 를 표현하면 max == range 가 되어 우선 깔끔해 보이지만,
0도 1도 무척 중요하고 정규화라는 편의성을 제공해주기 때문에 Max 를 Range 로 두는건 뒷단에서의 노가다를 감수해야하는거다.
자기 코드 안에 이곳은 수론 저곳은 집합론의 표현으로 구현해두면 헷갈릴 수 밖에 없겠지.
/*
대부분의 시스템에서 max는 range 일 수 없다.
dreg 는 서로 다른 시스템간의 변환에서 사람의 인식을 돕기위해서나 위치를 존재하게 하기 위한 필요악이다.
우리는 흔히 dreg 문제를 해결하기 위해 반올림이나 버림 따위의 애매한 선택을 하기도 하고,
그 애매한 선택은 프로젝트 종료까지 너를 따라다닐거다. 어쩌면 영영 아쉬움으로 남을 수도 있고.
min 이 1이 되는 시스템이 많을 것 같냐?
하지만 min을 0으로 두면 어느방향으로든 나아가기 쉽다.
정규화를 통해 max를 1로 두면 아름답다. 그말은 많은 곳에 유용하게 쓰인다는거다.
1보다 작은 소숫점으로 나누면 1보다 큰 자연수를 곱하는 효과니까 -1. ~ +1 의 영역이 hot spot 이란거다.
삼각함수의 좁은각 특성이나 테일러 급수를 이용한 최적화에 이용하더라도 유리한 공간임엔 틀림없다.
*/
두 줄 요약.
위의 4가지 step 에서 1번이라도 수행하지 않을 수 있게 해주기 위해 0부터 시작하는 index 가 여러모로 유용하다고 생각.
어디까지나 개인 취향의 문제로 보이지만, 시작을 저렇게 해두지 않으면 뒤에서 늘어나는 코드와 수고는 자기 책임이다.
긴글은 개추야
키워드는 정규화. 서수가 서수의 도메인에만 존재하는 아주 국소의 경우가 아니라면 0부터 시작하는 index가 훨 유리하다. 구구단이나 성적처리 수준의 프로그램만 구경해온 애들에게는 min 1이 좋아보일지도.
이해가 잘 안되는 부분이 훨씬 많당.... 근데 맨위에 표현을 저렇게할 수있구나 지젼... 많이배워갑니당
도메인이 모죠?
몇번 읽어보니까 눈에 들어오네여
아... 그러네요.
여기서 도메인이란 분야, 영역이란 뜻으로 쓰고 있어.
좀 더 쉽게 써주고 싶지만 그러면 글이 너무 길어질것 같아서 말야. 미안하다.
우리는 2진법을 디지틀 컴퓨터 내부에서 쓰고 있고, boolean 을 써서 참과 거짓을 표현하며, 이러한 boolean algebra 를 지원하는 논리 분기 명령어들을 갖고 있다.
따라서 누군가가 if (조건) puts("참"); else puts("거짓"); 의 branch 를 쓸때, 파이프라인이 깨지는 문제를 해결해주는데도 배열을 활용할 수 있다.
const char* boolStrings[] = {"거짓", "참}; 으로 선언해 뒀다면, 반복되는 빠른 연산이 필요한 부분에서 branch 없이 puts(boolStrings[조건]); 하나로 끝난다는거다.
배열의 인덱스가 0부터 시작하지 않고 1부터 시작했다면, puts(boolStrings[조건 + 1]); 을 했어야 했겠지. 지저분할 뿐더러 성능도 떨어진다. 이런걸 원하냐?
0은 어떤걸 곱해도 0이라 곱셈에 대한 결과가 상수고, 1은 어떤걸 곱해도 결과가 그 곱한 자신이라서 이 둘을 모두 다 활용하는 정규화가 많은 상호 간섭 문제를 해결해 준다.
정규 직교란 말이 수학적으로 갖는 의의는 정말 기본적이기 때문에 큰 것이다. 데카르트가 달리 똑똑한게 아냐.
위의 boolStrings[조건] 이란 부분은, boolean algebra 의 domain 에 있는 값을 ordinal 의 domain 으로 가지고 온거다. 이렇듯 우린 서로 다른 domain 과 domain 사이의 변환을 빈번하게 사용하게 된다. 수학은 수학 내에서만 존재하는게 아니라, 세상을 좀 더 사용하기 편한 도마와 작업대 위에 올려놓고 풀기 위해 필요한것이고, 프로그래밍과 컴퓨터 역시 마찬가지다.
히야 이 정도급의 설명은 처음들어봄. 코드세이퍼성님은 현업 개발자중에서 어떤 위치에여?
foremost
위에 "참 뒤에 따옴표 하나 빠뜨린거 이해해라. 즉석에서 쓴 글이라.
이 글도 여전히 range measure와 discrete counting의 개념을 섞어서 쓰고 있는 것 같은데요. 다익스트라의 글을 다시 풀어 쓴 느낌이에요.
매스매티카나 MATLAB, Julia등은 여전히 one based index를 쓰고 있는데, 이들이 잘못된(혹은 일부러 귀찮은 작업을 유발하는) 디자인을 갖고 있는 것 같지는 않습니다.
걔넨 기존 행렬연산의 1부터 시작하는 서수를 존중하니까 그런거지. 하부 구현을 사용자에게 맡기지 않잖아.
응용단만 건드리고 성능이 중요하지 않다면야 뭣부터 시작하면 어때? 난 다익스트라의 글을 읽어본적 없음. 누구 글을 참고한것도 아님.
처음에 파스칼을 언급한것도. 파스칼처럼 자유도를 줄 수 있으면 그걸로 족하다는거, 다만 0부터 시작하는 배열은 0을 안쓰고 1부터 시작해도 상관없지만, 애초에 1부터 시작하는 배열은 0부터 시작해야 하는 태그를 활용할때 추가 연산이 필요하다는게 바보같은 것.
그리고 내가보기엔 넌 이 글의 뜻을 이해 못했다.
좋은 설명이지만, C언어에서 배열의 인덱스를 0부터 시작하는 것은 생각보다 아주 간단한 이유임. 배열은 메모리 상에 연속된 데이터의 집합이고 Index를 0부터 시작하는 편이 메모리와 매핑할 때 불필요한 뺄셈 연산을 없앨 수 있기 때문이지. 일차원 배열이라면 연산 하나 차이지만 차원이 하나씩 늘어날 수록 뺄셈 연산은 증가하겠지.
그 이야긴 옛날에 다 했는데. 포인터와 베이스 레지스터 이야기
ㄴ 성능 차이나는 예 10가지 들어줄까? 얼마 내기할래?
일부러 반박못하게 할려고 어렵그 쓴듯? 뭔말인지 모르것당
유저라이프에 등록되었습니다. 감사합니다.
프로그래밍 생각보다 쉽네. 아니면 이 새끼가 쉽게 표현해서 그런건가? 암튼 잘 읽어보고 간다잉
글이나 댓글이나 허세끼 가득해서 혐
대학 공돌이인데 현재 랜덤 프로세스에서 가우시안 정규분포배운다. 백색잡음이라고 해서 정규분포 배우는데 이게 총적분값이 1이다. 이과충들은 알겠지만 정규분포 상당히 여기저기 많이 쓰이더라
게다가 글쓴이가 밝혔듯 정규 분포식 영상처리에서도 쓰인다.스테레오 영상 구하는거 연구해본적잇는데 첫 코드보고 내가 쓰던 코드랑 똑같아서 흥미생겨 다 읽어봄.정규화 하는방법만 배웟지 왜써먹는지 몰랏는데 조금 감이 잡힌것같다. 부랄을 탁 치고간다 이기야!!
그래서 julia, R같이 1부터 인덱스가 시작하는게 c나 python보다 구리다는거냐? 존나 말만 꼬아놨지 지가 무슨말 하는지 쳐 알면서 씨부리나? 인덱스 범위가지고 연산하는 효율 얘기하는데 대체 정규화를 왜갖다대 ㅋㅋ 제목은 오줌마려울때 짓고, 시원하게 싸지르고 키보드잡았냐? 이런부류가 말 존나어렵게해서 아는척한후에 사기치는 새끼들임
아닛 프갤이 유저라이프라니... 예전에 모바일기기에서 코딩하는거 이후로 처음보네
?
띠용
프갤이 해냇다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
이 흥미로운 논쟁에 참여하고싶지만 유저라이프라니 시발ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
이게 왜 펀이슈?
노오오오잼
ㅁㅈㅎ
이걸보고 허세가 있다는건 진짜 얼마나 현실이 쓰레기면 피해의식이 생길까..
지나가는 낙엽만봐도 상대적박탈감 느낀다는게 디시인이라지만...
내가 알아듣지 못한다 = 허세 빼애액
김치맨들은 'X가 Y보다 좋다'면 무조건 세상 모든게 X여야 하나봄ㅋㅋ 인덱스 시작값을 0으로주는 게 있고 1로 주는게 있는거시지
만든놈 취향 차이라는데 왜 '누구누구는 Y 쓰는데? 왜 X가 제일좋음?'(제일좋다고 한적도 없음)
엌
코드세이퍼갑 오늘도 좋은글 감사
오호 읽어보니 꽤 좋은 내용이다
\"인덱스 시작은 수학적 비주얼로나 성능에서나 0이 1보다 깔끔하고 멋찌당\" 이게 글쓴이 생각인데 \"뭐라구요??? 그래서 R이 구리다고욧?!\" 이렇게 베베 꼬아서 이해하니 문제