나는 해가 뜨기 전에 걸을 때 손전등 두 개를 가지고 다닙니다. 각각은 약 5시간의 배터리를 가지고 있으며 산책은 약 1시간 동안 지속됩니다. 나는 손전등이 다 떨어질 때까지 같은 손전등을 사용하려고 노력하고, 약 5일마다 산책하는 동안 불을 바꾸게 됩니다. 오래된 조명이 충전되면 다음 날 어떤 조명을 사용할지 기억하려고 노력합니다. 이 계획은 다음날 조명을 바꾸는 것을 잊어버린 경우에도 실제로 꽤 잘 작동합니다.
하지만 매일 손전등을 무작위로 선택하면 어떻게 될까요? 15분 동안 두 개의 조명이 있고 걷기 후반부에는 조명이 없는 경우가 얼마나 자주 발생합니까? 첨부된 JSL은 질문에 답하기 위한 시뮬레이션입니다. 먼저 답을 봅시다:
The red dots below 0 show where the two flashlights both failed, and how badlyThe red dots below 0 show where the two flashlights both failed, and how badlyThe red dots below 0 show where the two flashlights both failed, and how badlyThe red dots below 0 show where the two flashlights both failed, and how badly0 아래의 빨간색 점은 두 손전등이 모두 실패한 위치와 심각도를 나타냅니다.
제목 표시줄에는 이 시뮬레이션이 두 개의 조명에 대한 것이라고 나와 있습니다. 하나는 4시간 이상 배터리를 사용하고 다른 하나는 5시간 이상 배터리를 사용합니다. 대부분의 날에는 한 쌍의 조명이 몇 시간 남았습니다. JSL은 사용자 함수로 시작합니다. 화장대 , 다른 그래프를 만들기 위해 코드가 아래에서 재사용되기 때문입니다.
maketable = function({capacity},// an array with the battery capacities expressed as time
{dt,charge,ontime,today,remainingWalkTime,message,light,usage,deadBatteries},//locals
{ 중괄호 }의 첫 번째 세트는 함수에 대한 매개변수를 보유합니다. 용량 , 이는 각 손전등의 시간 용량을 포함하는 작은 행렬이 됩니다. 두 번째 세트는 함수에 대한 지역 변수를 보유합니다. 함수를 호출하는 JSL이 동일한 변수 이름을 사용하는 경우 호출자의 변수는 이 함수에 의해 변경되지 않습니다.
charge = capacity; // charge[] tracks the remaining charge
// expression that computes random on time for flashlight
ontime = Expr(
As Date( In Hours( Min( 2, Max( .5, Random Normal( 1, .1 ) ) ) ) ) // usually about 1-hour walk
);
// table to collect results
dt = New Table( "Light Schedule",
Add Rows( 1 ),
New Column( "day", Numeric, "Ordinal", Format( "m/d/y", 10 ), Input Format( "m/d/y" ), Set Values( {1feb2020} ) ),
New Column( "hoursAvailable", Numeric, "Continuous", Format( "hr:m", 12 ), Set Values( {sum(charge)} ) ),
New Column( "notes", Character, Set Values( {"Two fully charged lights"} ), Set Display Width( 500 ) ),
Set Label Columns( :notes )
);
위의 경우, 복사를 통해 처음에는 배터리가 완전히 충전됩니다. 용량 ~ 안으로 요금 . 그런 다음 표현식이 다음에 할당됩니다. 정시 , 이는 내 산책 시간의 분포를 나타냅니다. 대략 한 시간 정도입니다. 그리고 마지막으로, dt 이 함수가 결국 호출자에게 반환될 새 데이터 테이블로 설정됩니다. 표에는 하루 카운터 열, 산책 후 손전등을 사용할 수 있는 시간을 표시하는 열, 발생한 일에 대해 컴퓨터에서 생성된 메모가 포함된 열이 포함되어 있습니다.
// run the simulation for about 10 years
For( today = 2feb2020, today <= 2dec2029, today += In Days( 1 ),
remainingWalkTime = ontime; // gets a new random duration for the length of an early morning walk
message = Format( remainingWalkTime, "hr:m" ) || " --"; // total walk duration
While( remainingWalkTime > 0 & Sum( charge ) > 0, // also give up when there are no charged lights remaining
// choosing randomly might be too slow if there are many uncharged lights, but there are only 2 or 3...
light = Random Integer( N Rows( capacity ) ); // choose from available lights
If( charge[light] > 0, // if it is a charged light, use it
usage = Min( remainingWalkTime, charge[light] ); // only take what is needed, up to available charge
remainingWalkTime -= usage;
charge[light] -= usage;
message ||= " light " || Char( light ) || "(" || Format( usage, "hr:m" ) || ")";
);
);
위 시뮬레이션 루프의 첫 번째 부분은 2020년부터 2030년까지 반복됩니다. (날짜는 그래프에 레이블을 지정하는 것 외에는 실제로 사용되지 않습니다. 기간은 대략 10*365일입니다. 나중에 표에서 약 3500개의 행을 볼 수 있습니다.) 남은걷기시간 약 1시간으로 설정되어 초기값이 됩니다. 메시지 , 오늘의 메모가 될 추가 텍스트가 포함됩니다. For 루프 내부에는 걷기의 일부에 대해 손전등을 무작위로 선택하는 While 루프가 있습니다. For 루프는 걷기가 끝나거나 남은 충전량이 있는 손전등이 없을 때까지 계속해서 손전등을 선택합니다. 선택한 조명은 모두 사용되거나 걷기를 완료하는 데 충분하게 사용됩니다. 그런 다음 어떤 조명이 얼마나 오랫동안 사용되었는지 알려주기 위해 메시지가 업데이트됩니다.
// update data table
dt << addrows( 1 );
If( remainingWalkTime > 0,
Row State() = Color State( "red" );
// the next line makes the charge go below zero on the first battery;
// that makes column 1 have negative numbers, and makes the graph do
// a better job of visualizing how long the walk in the dark lasted.
message ||= " walked in the dark(" || Format( remainingWalkTime, "hr:m" ) || ")";
charge[1] -= remainingWalkTime;
remainingWalkTime = 0; // maybe the sun is coming up
);
dt:day = today;
dt:hoursAvailable = sum(charge);
dt:notes = message;
// recharge any dead batteries
deadBatteries = Loc( charge <= 0 );
charge[deadBatteries] = capacity[deadBatteries];
message ||= " recharged" || Char( deadBatteries );
);
위 시뮬레이션의 마지막 부분에서는 테이블에 행을 추가하여 다음을 나타냅니다. 오늘 , 있는 경우 빨간색으로 표시됩니다. 남은걷기시간 남겨두고 설정합니다. 낮 , 시간가능 , 그리고 노트 새 행에 대해. 마지막으로 배터리가 재충전됩니다. 그만큼 위치 함수는 전하 행렬에서 0 아래로 떨어진 인덱스 또는 위치를 찾습니다. 그런 다음 해당 위치에 대해서만 충전 값이 용량 값으로 재설정됩니다.
dt; // return value
);
그리고 (위) 기능이 종료됩니다. 마지막 문의 값이 호출자에게 반환됩니다. dt 는 그 자체로 다음과 같이 평가되는 정말 간단한 명령문입니다. dt . 반환 기능을 사용할 수도 있습니다. 반환(dt); 함수의 어느 곳에서나.
// the following line determines how many flashlights are in the simulation
capacity = matrix({In Hours( 4.3 ),In Hours( 5.6 )}); // one battery is much older, less capacity.
dt = maketable(capacity);
// graph the results
dt << Graph Builder(
Size( 1388, 500 ),
Show Control Panel( 0 ),
Show Legend( 0 ),
Variables( X( :day ), Y( :hoursAvailable ) ),
Elements( Points( X, Y, Legend( 9 ) ) ),
SendToReport(
Dispatch( {}, "Graph Builder", OutlineBox, {Set Title( title="h:m battery capacities: "; for(icap=1,icap<=nRows(capacity),icap+=1,title||=format(capacity[icap],"hr:m")||" ";); title )} ),
Dispatch({},"day",ScaleBox, {Format( "m/d/y", 10 ), Min( 3660681600 ), Max( 3976300800 ), Interval( "Year" ), Inc( 2 ), Minor Ticks( 0 )}),
Dispatch( {}, "graph title", TextEditBox, {Set Text( "Available flashlight time at end of walk" )} ),
Dispatch( {}, "Y title", TextEditBox, {Set Text( "Hours:Minutes" )} ),
Dispatch( {}, "400", LegendBox, {Set Title( "" )} )
)
);
마지막으로 위에서 전화하세요. 화장대 와 용량 이는 두 개의 배터리를 정의합니다. 그만큼 dt = 왼쪽에는 = 오른쪽에 있는 함수의 결과가 할당된 전역 변수가 있습니다. 그만큼 dt 함수가 함수 시작 부분의 로컬 목록에 있고 전역을 변경하지 않습니다. dt . 데이터 테이블이 생성되면 그래프 빌더에서 그래프를 만들 수 있습니다(위쪽). 그래프 빌더 스크립트를 처음부터 작성하지 마세요! GUI를 사용하여 원하는 것을 얻은 다음 스크립트를 저장하십시오. 배터리 용량과 함께 사용자 정의 개요 제목을 추가하기 위해 이것을 편집했습니다.
그래프 빌더(위)가 사용한 테이블은 다음과 같습니다.
Output from maketable() function showing (negative) hours and notesOutput from maketable() function showing (negative) hours and notesOutput from maketable() function showing (negative) hours and notesOutput from maketable() function showing (negative) hours and notes(음수) 시간과 메모를 표시하는 maketable() 함수의 출력
maketable()은 배터리 용량에 대한 인수를 취하므로 여러 번 실행할 수 있습니다. 손전등을 추가로 가지고 다닐 계획은 없지만, 손전등의 수와 용량이 문제를 가장 잘 해결하는지 알고 싶습니다. 다음은 루프에서 maketable을 호출하고 maketable이 반환하는 테이블에서 또 다른 응답 테이블을 수집하는 일부 JSL입니다.
// make a table-of-tables; use from 1 to 10 flashlights with batteries from 1/16 to 32 hours
dtreport = New Table( "lights",
New Column( "nBats", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "batSize", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "nfailures", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "darkHours", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) )
);
dtreport 집계된 답변을 보관할 데이터 테이블입니다.
For( nLights = 1, nLights <= 10, nLights += 1,
For( batLife = 1 / 16, batLife <= 32, batLife *= 2,
dt = maketable( Repeat( inhours(batLife), nLights ) );
위에서 한 쌍의 루프는 100개의 조합을 통해 실행되어 새로운 dt 매번.
// count the failures and duration of failures
remaining = dt[0, "hoursAvailable"];
failures = Loc( remaining < 0 );
nfail = N Rows( failures );
darkSum = As Date( -Sum( remaining[failures] ) );
dtreport<<ADDROWS></ADDROWS>
위에, 남은 움켜잡는다 시간가능 열을 행렬로 사용하여 사용할 수 있습니다. 위치() 다시 찾기 위해 실패.실패 횟수와 총 실패 시간을 실험해 보았는데, 그래프에서도 비슷한 결과를 얻었습니다. 행을 추가합니다. dtreport 표를 작성하고 작성하세요.
Close( dt, "nosave" );
)
);
더 이상 필요하지 않으면 루프에서 dt 테이블을 닫아 100개의 창이 열리지 않도록 하세요.
이제 방금 생성된 테이블은 다음과 같습니다.
.0625 hour will probably never be enough, even with 10 flashlights.0625 hour will probably never be enough, even with 10 flashlights.0625 hour will probably never be enough, even with 10 flashlights.0625 hour will probably never be enough, even with 10 flashlights.0625시간은 아마도 10개의 손전등을 사용해도 결코 충분하지 않을 것입니다.
더 많은 조명과 더 나은 배터리가 도움이 된다는 것을 알 수 있습니다. JSL(그래프 빌더의 GUI에서 저장됨)은 다음과 같습니다.
dtreport<<GRAPH builder=""></GRAPH>
결과 그래프는 다음과 같습니다.
More flashlights or more batteries keeps me out of the darkMore flashlights or more batteries keeps me out of the darkMore flashlights or more batteries keeps me out of the darkMore flashlights or more batteries keeps me out of the dark더 많은 손전등이나 더 많은 배터리로 인해 어둠 속에서도 벗어날 수 있습니다.
등고선 플롯은 100번의 시뮬레이션 결과를 보여줍니다. 17시간 용량의 손전등 3개 또는 8시간 용량의 손전등 4개로 충분할 것으로 보입니다. 하지만 손전등이 두 개뿐이고, 조명을 무작위로 선택하고, 죽은 경우에만 충전하면 조명을 계속 켜둘 수 있는 용량이 없을 수도 있습니다.