File:  [LON-CAPA] / loncom / homework / default_homework.lcpm
Revision 1.84: download - view: text, annotated - select for diffs
Thu May 27 04:25:13 2004 UTC (19 years, 11 months ago) by albertel
Branches: MAIN
CVS tags: HEAD
- fixes for randnumber generation
   - due to a error in coding the 64bit and 64bit2 rnd seeds were throwing away the second half of the seed, we now preserve this functionality and make it explicit
   - additionally 64bit3 now uses all 64bits of the seed
   - also added new function pushrandomnumber poprandomnumber to be called instead of setrandomnumber before we were crunching the Safe space random number generator state, as this function is used bu thing the <optionresponse> and <radoibuttonresponse> this meant changes in the internal randomization code could screw up later Safe space random calls the old method is preserved for blank 64bit and 64bit2 randomiztion env.

    1: # The LearningOnline Network with CAPA 
    2: # used by lonxml::xmlparse() as input variable $safeinit to Apache::run::run()
    3: #
    4: # $Id: default_homework.lcpm,v 1.84 2004/05/27 04:25:13 albertel Exp $
    5: #
    6: # Copyright Michigan State University Board of Trustees
    7: #
    8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    9: #
   10: # LON-CAPA is free software; you can redistribute it and/or modify
   11: # it under the terms of the GNU General Public License as published by
   12: # the Free Software Foundation; either version 2 of the License, or
   13: # (at your option) any later version.
   14: #
   15: # LON-CAPA is distributed in the hope that it will be useful,
   16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18: # GNU General Public License for more details.
   19: #
   20: # You should have received a copy of the GNU General Public License
   21: # along with LON-CAPA; if not, write to the Free Software
   22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   23: #
   24: # /home/httpd/html/adm/gpl.txt
   25: #
   26: # http://www.lon-capa.org/
   27: #
   28: #
   29: 
   30: #init some globals
   31: $hidden::RANDOMINIT=0;
   32: $pi=atan2(1,1)*4;
   33: $rad2deg=180.0/$pi;
   34: $deg2rad=$pi/180.0;
   35: $"=' ';
   36: 
   37: sub caparesponse_check {
   38:     my ($answer,$response)=@_;
   39:     #not properly used yet: calc
   40:     #not to be used: $ans_fmt
   41:     my $type=$LONCAPA::CAPAresponse_args{'type'};
   42:     my $tol=$LONCAPA::CAPAresponse_args{'tol'};
   43:     my $sig=$LONCAPA::CAPAresponse_args{'sig'};
   44:     my $ans_fmt=$LONCAPA::CAPAresponse_args{'ans_fmt'};
   45:     my $unit=$LONCAPA::CAPAresponse_args{'unit'};
   46:     my $calc=$LONCAPA::CAPAresponse_args{'calc'};
   47:     my $samples=$LONCAPA::CAPAresponse_args{'samples'};
   48:     
   49:     my $tol_type=''; # gets it's value from whether tol has a % or not done
   50:     my $sig_lbound=''; #done
   51:     my $sig_ubound=''; #done
   52: 
   53: 
   54:     #type's definitons come from capaParser.h
   55:     my $message='';
   56:     #remove leading and trailing whitespace
   57:     if (!defined($response)) {
   58: 	$response='';
   59:     }
   60:     if ($response=~ /^\s|\s$/) {
   61: 	$response=~ s:^\s+|\s+$::g;
   62: 	$message .="Removed ws now :$response:\n";
   63:     } else {
   64: 	$message .="no ws in :$response:\n";
   65:     }
   66:     if ($type eq 'cs' || $type eq 'ci' || $type eq 'mc') {
   67: 	#for string answers make surec all places spaces occur, there is 
   68:         #really only 1 space, in both the answer and the response
   69: 	$answer=~s/ +/ /g;
   70: 	$response=~s/ +/ /g;
   71:     }
   72:     if ($type eq 'float') { $response=~s/,//g; }
   73:     if (length($response) > 500) { return "TOO_LONG: Answer too long"; }
   74: 
   75:     if ($type eq '' ) {
   76: 	$message .= "Didn't find a type :$type: defaulting\n";
   77: 	if ( $answer eq ($answer *1.0)) { $type = 2;
   78: 				      } else { $type = 3; }
   79:     } else {
   80: 	if ($type eq 'cs')    { $type = 4; }
   81: 	elsif ($type eq 'ci')    { $type = 3 }
   82: 	elsif ($type eq 'mc')    { $type = 5; }
   83: 	elsif ($type eq 'fml')   { $type = 8; }
   84: 	elsif ($type eq 'subj')  { $type = 7; }
   85: 	elsif ($type eq 'float') { $type = 2; }
   86: 	elsif ($type eq 'int')   { $type = 1; }
   87: 	else { return "ERROR: Unknown type of answer: $type" }
   88:     }
   89: 
   90:     my $points;
   91:     my $id_list;
   92:     #formula type setup the sample points
   93:     if ($type eq '8') {
   94: 	($id_list,$points)=split(/@/,$samples);
   95: 	$message.="Found :$id_list:$points: points in $samples\n";
   96:     }
   97:     if ($tol eq '') {
   98: 	$tol=0.0;
   99: 	$tol_type=1; #TOL_ABSOLUTE
  100:     } else {
  101: 	if ($tol =~ /%$/) {
  102: 	    chop $tol;
  103: 	    $tol_type=2; #TOL_PERCENTAGE
  104: 	} else {
  105: 	    $tol_type=1; #TOL_ABSOLUTE
  106: 	}
  107:     }
  108: 
  109:     if ($sig eq '') {
  110: 	$sig_lbound = 0; #SIG_LB_DEFAULT
  111: 	$sig_ubound =15; #SIG_UB_DEFAULT
  112:     } else {
  113: 	($sig_lbound,$sig_ubound) = split /,/,$sig;
  114: 	if (!defined($sig_lbound)) {
  115: 	    $sig_lbound = 0; #SIG_LB_DEFAULT
  116: 	    $sig_ubound =15; #SIG_UB_DEFAULT
  117: 	}
  118: 	if (!defined($sig_ubound)) { $sig_ubound=$sig_lbound; }
  119:     }
  120:     my $reterror="";
  121:     my $result = &caparesponse_capa_check_answer($response,$answer,$type,
  122: 						 $tol_type,$tol,
  123: 						 $sig_lbound,$sig_ubound,
  124: 						 $ans_fmt,$unit,$calc,$id_list,
  125: 						 $points,$external::randomseed,
  126: 						 \$reterror);
  127: 
  128:     if    ($result == '1') { $result='EXACT_ANS'; } 
  129:     elsif ($result == '2') { $result='APPROX_ANS'; }
  130:     elsif ($result == '3') { $result='SIG_FAIL'; }
  131:     elsif ($result == '4') { $result='UNIT_FAIL'; }
  132:     elsif ($result == '5') { $result='NO_UNIT'; }
  133:     elsif ($result == '6') { $result='UNIT_OK'; }
  134:     elsif ($result == '7') { $result='INCORRECT'; }
  135:     elsif ($result == '8') { $result='UNIT_NOTNEEDED'; }
  136:     elsif ($result == '9') { $result='ANS_CNT_NOT_MATCH'; }
  137:     elsif ($result =='10') { $result='SUB_RECORDED'; }
  138:     elsif ($result =='11') { $result='BAD_FORMULA'; }
  139:     elsif ($result =='13') { $result='UNIT_INVALID_INSTRUCTOR'; }
  140:     elsif ($result =='141') { $result='UNIT_INVALID_STUDENT'; }
  141:     elsif ($result =='142') { $result='UNIT_INVALID_STUDENT'; }
  142:     elsif ($result =='143') { $result='UNIT_INVALID_STUDENT'; }
  143:     elsif ($result =='15') { $result='UNIT_IRRECONCIBLE'; }
  144:     else  {$result = "ERROR: Unknown Result:$result:$@:";}
  145: 
  146:     return ("$result:\nRetError $reterror:\nAnswer $answer:\nResponse $response:\n type-$type|$tol|$tol_type|$sig:$sig_lbound:$sig_ubound|$unit|\n$message",$reterror);
  147: }
  148: 
  149: 
  150: sub caparesponse_check_list {
  151:     my $response=$LONCAPA::CAPAresponse_args{'response'};
  152:     my ($result,@list);
  153:     @list=@LONCAPA::CAPAresponse_answer;
  154:     my $aresult='';
  155:     my $current_answer;
  156:     my $answers=join(':',@list);
  157:     $result.="Got response :$answers:\n";
  158:     &LONCAPA_INTERNAL_DEBUG("<blink>Yo!</blink> got ".join(':',%LONCAPA::CAPAresponse_args));
  159:     my @responselist;
  160:     my $type = $LONCAPA::CAPAresponse_args{'type'};
  161:     $result.="Got type :$type:\n";
  162:     if ($type ne '' && $#list > 0) {
  163: 	(@responselist)=split /,/,$response;
  164:     } else {
  165: 	(@responselist)=($response);
  166:     }
  167:     my $unit='';
  168:     $result.="Initial final response :$responselist['-1']:\n";
  169:     if ($type eq '' || $type eq 'float') {
  170: 	#for numerical problems split off the unit
  171: 	if ( $responselist['-1']=~ /(.*[^\s])\s+([^\s]+)/ ) {
  172: 	    $responselist['-1']=$1;
  173: 	    $unit=$2;
  174: 	}
  175:     }
  176:     $result.="Final final response :$responselist['-1']:$unit:\n";
  177:     $result.=":$#list: answers\n";
  178:     $unit=~s/\s//;
  179:     my $i=0;
  180:     my $awards='';
  181:     my @msgs;
  182:     for ($i=0; $i<@list;$i++) {
  183: 	my $msg;
  184: 	$result.="trying answer :$list[$i]:\n";
  185: 	my $thisanswer=$list[$i];
  186: 	$result.="trying answer :$thisanswer:\n";
  187: 	if ($unit eq '') {
  188: 	    ($aresult,$msg)=&caparesponse_check($thisanswer,$responselist[$i]);
  189: 	} else {
  190: 	    ($aresult,$msg)=&caparesponse_check($thisanswer,
  191: 						$responselist[$i]." $unit");
  192: 	}
  193: 	my ($temp)=split /:/, $aresult;
  194: 	$awards.="$temp,";
  195: 	$result.=$aresult;
  196: 	push(@msgs,$msg);
  197:     }
  198:     chop $awards;
  199:     return ("$awards:\n$result",@msgs);
  200: }
  201: 
  202: sub tex {
  203:     if ( $external::target eq "tex" ) {
  204: 	return $_[0];
  205:     } else {
  206: 	return $_[1];
  207:     }
  208: }
  209: 
  210: sub var_in_tex {
  211:     if ( $external::target eq "tex" ) {
  212: 	return $_[0];
  213:     } else {
  214: 	return "";
  215:     }
  216: }
  217: 
  218: sub web {
  219:     if ( $external::target eq "tex" ) {
  220: 	return $_[1];
  221:     } else {
  222: 	if ( $external::target eq "web" || $external::target eq "answer") {
  223: 	    return $_[2];
  224: 	} else {
  225: 	    return $_[0];
  226: 	}
  227:     }
  228: }
  229: 
  230: sub html {
  231:     if ( $external::target eq "web" ) {
  232: 	return shift;
  233:     }
  234: }
  235: 
  236: sub hinton {
  237:     return 0;
  238: }
  239: 
  240: sub random {
  241:     my ($start,$end,$step)=@_;
  242:     if ( ! $hidden::RANDOMINIT ) {
  243: 	if ($external::randomseed == 0) { $external::randomseed=1; }
  244: 	if ($external::randomseed =~/,/) {
  245: 	    my ($num1,$num2)=split(/,/,$external::randomseed);
  246: 	    &random_set_seed(1,abs($num1));
  247: 	} elsif ($external::randomseed =~/:/) {
  248: 	    my ($num1,$num2)=split(/:/,$external::randomseed);
  249: 	    &random_set_seed(abs($num1),abs($num2));
  250: 	} else {
  251: 	    &random_set_seed(1,int(abs($external::randomseed)));
  252: 	}
  253: 	&math_random_uniform();
  254: 	$hidden::RANDOMINIT=1;
  255:     }
  256:     if (!defined($step)) { $step=1; }
  257:     my $num=1+int(($end-$start)/$step);
  258:     my $result=$start + int(&math_random_uniform() * $num)*$step;
  259:     return $result;
  260: }
  261: 
  262: sub random_normal {
  263:     my ($item_cnt,$seed,$av,$std_dev) = @_;
  264:     my @oldseed=&random_get_seed();
  265:     my @retArray;
  266:     &random_set_seed_from_phrase($seed);
  267:     @retArray=&math_random_normal($item_cnt,$av,$std_dev);
  268:     &random_set_seed(@oldseed);
  269:     return @retArray;
  270: }
  271: 
  272: sub random_beta {
  273:     my ($item_cnt,$seed,$aa,$bb) = @_;
  274:     my @oldseed=&random_get_seed();
  275:     my @retArray;
  276:     &random_set_seed_from_phrase($seed);
  277:     @retArray=&math_random_beta($item_cnt,$aa,$bb);
  278:     &random_set_seed(@oldseed);
  279:     return @retArray;
  280: }
  281: 
  282: sub random_gamma {
  283:     my ($item_cnt,$seed,$a,$r) = @_;
  284:     my @oldseed=&random_get_seed();
  285:     my @retArray;
  286:     &random_set_seed_from_phrase($seed);
  287:     @retArray=&math_random_gamma($item_cnt,$a,$r);
  288:     &random_set_seed(@oldseed);
  289:     return @retArray;
  290: }
  291: 
  292: sub random_exponential {
  293:     my ($item_cnt,$seed,$av) = @_;
  294:     my @oldseed=&random_get_seed();
  295:     my @retArray;
  296:     &random_set_seed_from_phrase($seed);
  297:     @retArray=&math_random_exponential($item_cnt,$av);
  298:     &random_set_seed(@oldseed);
  299:     return @retArray;
  300: }
  301: 
  302: sub random_poisson {
  303:     my ($item_cnt,$seed,$mu) = @_;
  304:     my @oldseed=&random_get_seed();
  305:     my @retArray;
  306:     &random_set_seed_from_phrase($seed);
  307:     @retArray=&math_random_poisson($item_cnt,$mu);
  308:     &random_set_seed(@oldseed);
  309:     return @retArray;
  310: }
  311: 
  312: sub random_chi {
  313:     my ($item_cnt,$seed,$df) = @_;
  314:     my @oldseed=&random_get_seed();
  315:     my @retArray;
  316:     &random_set_seed_from_phrase($seed);
  317:     @retArray=&math_random_chi_square($item_cnt,$df);
  318:     &random_set_seed(@oldseed);
  319:     return @retArray;
  320: }
  321: 
  322: sub random_noncentral_chi {
  323:     my ($item_cnt,$seed,$df,$nonc) = @_;
  324:     my @oldseed=&random_get_seed();
  325:     my @retArray;
  326:     &random_set_seed_from_phrase($seed);
  327:     @retArray=&math_random_noncentral_chi_square($item_cnt,$df,$nonc);
  328:     &random_set_seed(@oldseed);
  329:     return @retArray;
  330: }
  331: 
  332: sub random_f {
  333:     my ($item_cnt,$seed,$dfn,$dfd) = @_;
  334:     my @oldseed=&random_get_seed();
  335:     my @retArray;
  336:     &random_set_seed_from_phrase($seed);
  337:     @retArray=&math_random_f($item_cnt,$dfn,$dfd);
  338:     &random_set_seed(@oldseed);
  339:     return @retArray;
  340: }
  341: 
  342: sub random_noncentral_f {
  343:     my ($item_cnt,$seed,$dfn,$dfd,$nonc) = @_;
  344:     my @oldseed=&random_get_seed();
  345:     my @retArray;
  346:     &random_set_seed_from_phrase($seed);
  347:     @retArray=&math_random_noncentral_f($item_cnt,$dfn,$dfd,$nonc);
  348:     &random_set_seed(@oldseed);
  349:     return @retArray;
  350: }
  351: 
  352: sub random_multivariate_normal {
  353:     my ($item_cnt,$seed,$mean,$covar) = @_;
  354:     my @oldseed=&random_get_seed();
  355:     &random_set_seed_from_phrase($seed);
  356:     @retArray=&math_random_multivariate_normal($item_cnt,@$mean,@$covar);
  357:     &random_set_seed(@oldseed);
  358:     return @retArray;
  359: }
  360: 
  361: sub random_multinomial {
  362:     my ($item_cnt,$seed,@p) = @_;
  363:     my @oldseed=&random_get_seed();
  364:     my @retArray;
  365:     &random_set_seed_from_phrase($seed);
  366:     @retArray=&math_random_multinomial($item_cnt,@p);
  367:     &random_set_seed(@oldseed);
  368:     return @retArray;
  369: }
  370: 
  371: sub random_permutation {
  372:     my ($seed,@inArray) = @_;
  373:     my @oldseed=&random_get_seed();
  374:     my @retArray;
  375:     &random_set_seed_from_phrase($seed);
  376:     @retArray=&math_random_permutation(@inArray);
  377:     &random_set_seed(@oldseed);
  378:     return @retArray;
  379: }
  380: 
  381: sub random_uniform {
  382:     my ($item_cnt,$seed,$low,$high) = @_;
  383:     my @oldseed=&random_get_seed();
  384:     my @retArray;
  385:     &random_set_seed_from_phrase($seed);
  386:     @retArray=&math_random_uniform($item_cnt,$low,$high);
  387:     &random_set_seed(@oldseed);
  388:     return @retArray;
  389: }
  390: 
  391: sub random_uniform_integer {
  392:     my ($item_cnt,$seed,$low,$high) = @_;
  393:     my @oldseed=&random_get_seed();
  394:     my @retArray;
  395:     &random_set_seed_from_phrase($seed);
  396:     @retArray=&math_random_uniform_integer($item_cnt,$low,$high);
  397:     &random_set_seed(@oldseed);
  398:     return @retArray;
  399: }
  400: 
  401: sub random_binomial {
  402:     my ($item_cnt,$seed,$nt,$p) = @_;
  403:     my @oldseed=&random_get_seed();
  404:     my @retArray;
  405:     &random_set_seed_from_phrase($seed);
  406:     @retArray=&math_random_binomial($item_cnt,$nt,$p);
  407:     &random_set_seed(@oldseed);
  408:     return @retArray;
  409: }
  410: 
  411: sub random_negative_binomial {
  412:     my ($item_cnt,$seed,$ne,$p) = @_;
  413:     my @oldseed=&random_get_seed();
  414:     my @retArray;
  415:     &random_set_seed_from_phrase($seed);
  416:     @retArray=&math_random_negative_binomial($item_cnt,$ne,$p);
  417:     &random_set_seed(@oldseed);
  418:     return @retArray;
  419: }
  420: 
  421: sub abs { abs(shift) }
  422: sub sin { sin(shift) }
  423: sub cos { cos(shift) }
  424: sub exp { exp(shift) }
  425: sub int { int(shift) }
  426: sub log { log(shift) }
  427: sub atan2 { atan2($_[0],$_[1]) }
  428: sub sqrt { sqrt(shift) }
  429: 
  430: sub tan  { CORE::sin($_[0]) / CORE::cos($_[0]) }
  431: #sub atan { atan2($_[0], 1); }
  432: #sub acos { atan2(sqrt(1 - $_[0] * $_[0]), $_[0] ); }
  433: #sub asin { atan2($_[0], sqrt(1- $_[0] * $_[0]) );  }
  434: 
  435: sub log10 { CORE::log($_[0])/CORE::log(10); }
  436: 
  437: sub factorial {
  438:     my $input = CORE::int(shift);
  439:     return "Error - unable to take factorial of an negative number ($input)" if $input < 0;
  440:     return "Error - factorial result is greater than system limit ($input)" if $input > 170;
  441:     return 1 if $input == 0;
  442:     my $result = 1; 
  443:     for (my $i=2; $i<=$input; $i++) { $result *= $i }
  444:     return $result;
  445: }
  446: 
  447: sub sgn {
  448:     return -1 if $_[0] < 0;
  449:     return 0 if $_[0] == 0;
  450:     return 1 if $_[0] > 0;
  451: }
  452: 
  453: sub min {
  454:     my @sorted = sort { $a <=> $b || $a cmp $b } @_;
  455:     return shift @sorted;
  456: }
  457: 
  458: sub max {
  459:     my @sorted = sort { $a <=> $b || $a cmp $b } @_;
  460:     return pop @sorted;
  461: }
  462: 
  463: sub roundto {
  464:     my ($input,$n) = @_;
  465:     return sprintf('%.'.$n.'f',$input);
  466: }
  467: 
  468: sub to_string {
  469:     my ($input,$n) = @_;
  470:     return sprintf($input) if $n eq "";
  471:     $n = '.'.$n if $n !~ /^\./;
  472:     return sprintf('%'.$n,$input) if $n ne "";
  473: }
  474: 
  475: sub sub_string {
  476:     my ($str,$start,$len) = @_;
  477:     return substr($str,$start-1,$len);
  478: }
  479: 
  480: sub pow   {return $_[0] ** $_[1]; }
  481: sub ceil  {return (($_[0]-CORE::int($_[0]))== 0.0) ? $_[0] : (($_[0] > 0) ? (CORE::int($_[0])+ 1) : CORE::int($_[0])); }
  482: sub floor  {return (($_[0]-CORE::int($_[0]))== 0.0) ? $_[0] : (($_[0] > 0) ? CORE::int($_[0]) : (CORE::int($_[0])-1)); }
  483: #sub floor {return int($_[0]); }
  484: 
  485: sub format {
  486:     my ($value,$fmt)=@_;
  487:     my ($dollarmode,$commamode,$alwaysperiod,$options);
  488:     if ($fmt =~ /^([^\d]*)(.*)/) { $options=$1; $fmt=$2; } 
  489:     #if ($options =~ /\$/) { $dollamode=1; }
  490:     #if ($options =~ /,/)  { $commamode=1; }
  491:     if ($options =~ /\./) { $alwaysperiod=1; }
  492:     $fmt=~s/e/E/g;
  493:     my $result=sprintf('%.'.$fmt,$value);
  494:     if ($alwaysperiod && $fmt eq '0f') { $result .='.'; }
  495:     $result=~s/(E[+-]*)0/$1/;
  496:     #if ($dollarmode) {$result=&dollarformat($result);}
  497:     #if ($commamode) {$result=&commaformat($result);}
  498:     return $result;
  499: }
  500: 
  501: sub chemparse {
  502:     my ($reaction) = @_;
  503:     my @tokens = split(/(\s\+|\->|<=>)/,$reaction);
  504:     my $formula = '';
  505:     foreach my $token (@tokens) {
  506: 	if ($token eq '->' ) {
  507: 	    $formula .= '<m>\ensuremath{\rightarrow}</m> ';
  508: 	    next;
  509: 	}
  510: 	if ($token eq '<=>') {
  511: 	    if ($external::target eq 'web' &&
  512: 		&EXT('request.browser.unicode')) {
  513: 		$formula .= '&#8652; ';
  514: 	    } else {
  515: 		$formula .= &web('<=> ','<m>\ensuremath{\rightleftharpoons}</m> ',
  516: 				 '&lt;=$gt; ');
  517: 	    }
  518: 	    next;
  519: 	}
  520: 	$token =~ /^\s*(\d*)(.*)/;
  521: 	$formula .= $1 if ($1 > 1);  # stoichiometric coefficient
  522: 	
  523: 	my $molecule = $2;
  524: 	# subscripts
  525: 	$molecule =~ s|(?<=[a-zA-Z\)\]\s])(\d+)|<sub>$1</sub>|g;
  526: 	# superscripts
  527: 	$molecule =~ s|\^(\d*[+\-]*)|<sup>$1</sup>|g;
  528: 	# strip whitespace
  529: 	$molecule =~ s/\s*//g;
  530: 	# forced space
  531: 	$molecule =~ s/_/ /g;
  532: 	$formula .= $molecule.'&nbsp;';
  533:     }
  534:     # get rid of trailing space
  535:     $formula =~ s/(\Q${nbsp}\E| )$//;
  536:     
  537:     return &xmlparse($formula);
  538: }
  539: 
  540: sub prettyprint {
  541:     my ($value,$fmt,$target)=@_;
  542:     my $result;
  543:     if (!$target) { $target = $external::target; }
  544:     if ($fmt =~ /chem/i) { return(&chemparse($value)); }
  545:     my ($dollarmode,$commamode,$alwaysperiod,$options);
  546:     if ($fmt =~ /^([^\d]*)(.*)/) { $options=$1; $fmt=$2; } 
  547:     if ($options =~ /\$/) { $dollamode=1; }
  548:     if ($options =~ /,/)  { $commamode=1; }
  549:     if ($options =~ /\./) { $alwaysperiod=1; }
  550:     if ($fmt) { $value=sprintf('%.'.$fmt,$value); }
  551:     if ($alwaysperiod && $fmt eq '0f') {
  552: 	if ($target eq 'tex') {
  553: 	    $value .='\\ensuremath{.}';
  554: 	} else {
  555: 	    $value .='.';
  556: 	}
  557:     }
  558:     if ($value =~ /([0-9\.\-\+]+)E([0-9\-\+]+)/i ) {
  559: 	my $frac=$1;
  560: 	if ($dollarmode) { $frac=&dollarformat($frac); }
  561: 	if ($commamode) { $frac=&commaformat($frac); }
  562: 	my $exponent=$2;
  563: 	$exponent=~s/^\+0*//;
  564: 	$exponent=~s/^-0*/-/;
  565: 	$exponent=~s/^-0*/-/;
  566: 	if ($exponent eq '-') { undef($exponent); }
  567: 	if ($exponent) {
  568: 	    if ($target eq 'web') {
  569: 		$result=$frac.'&#215;10<sup>'.$exponent.'</sup>';
  570: 	    } elsif ($target eq 'tex') {
  571: 		$result='\ensuremath{'.$frac.'\times 10^{'.$exponent.'}}';
  572: 	    } else {
  573: 		$result=$value;
  574: 	    }
  575: 	} else {
  576: 	    $result=$frac;
  577: 	}
  578:     } else {
  579: 	$result=$value;
  580: 	if ($dollarmode) { $result=&dollarformat($result,$target); }
  581: 	if ($commamode) { $result=&commaformat($result,$target); }
  582:     }
  583:     return $result;
  584: }
  585: 
  586: sub commaformat {
  587:     my ($number,$target) = @_;
  588:     if ($number =~ /\./) {
  589: 	while ($number =~ /([^\.,]+)([^\.,][^\.,][^\.,])([,0-9]*\.[0-9]*)$/) {
  590: 	    $number = $1.','.$2.$3;
  591: 	}
  592:     } else {
  593: 	while ($number =~ /([^,]+)([^,][^,][^,])([,0-9]*)$/) {
  594: 	    $number = $1.','.$2.$3;
  595: 	}
  596:     }
  597:     return $number;
  598: }
  599: 
  600: sub dollarformat {
  601:     my ($number,$target) = @_;
  602:     if (!$target) { $target = $external::target; }
  603:     $number=&commaformat($number,$target);
  604:     if ($target eq 'tex') {
  605: 	$number='\$'.$number; #' stupid emacs
  606:     } else {
  607: 	$number='$'.$number; #' stupid emacs
  608:     }
  609:     return $number; 
  610: }
  611: 
  612: sub map {
  613:     my ($phrase,$dest,$source)=@_;
  614:     my @oldseed=&random_get_seed();
  615:     my @seed = &random_seed_from_phrase($phrase);
  616:     &random_set_seed(@seed);
  617:     my $destct = scalar(@$dest);
  618:     if (!$source) {
  619: 	my @output;
  620: 	my @idx = &math_random_permuted_index($destct);
  621: 	my $ctr = 0;
  622: 	while ($ctr < $destct) {
  623: 	    $output[$ctr] = $$dest[$idx[$ctr]];
  624: 	    $ctr++;
  625: 	}
  626:         &random_set_seed(@oldseed);
  627: 	return @output;
  628:     } else {
  629: 	my $num = scalar(@$source);
  630: 	my @idx = &math_random_permuted_index($num);
  631: 	my $ctr = 0;
  632: 	my $tot = $num;
  633: 	$tot = $destct if $destct < $num;
  634: 	if (ref($$dest[0])) {
  635: 	    while ($ctr < $tot) {
  636: 		${$$dest[$ctr]} = $$source[$idx[$ctr]];
  637: 	        $ctr++;
  638:             }
  639:         } else {
  640: 	    while ($ctr < $tot) {
  641: 		$$dest[$ctr] = $$source[$idx[$ctr]];
  642: 		$ctr++;
  643: 	    }
  644: 	}
  645:     }
  646:     &random_set_seed(@oldseed);
  647:     return '';
  648: }
  649: 
  650: sub rmap {
  651:     my ($phrase,$dest,$source)=@_;
  652:     my @oldseed=&random_get_seed();
  653:     my @seed = &random_seed_from_phrase($phrase);
  654:     &random_set_seed(@seed);
  655:     my $destct = scalar(@$dest);
  656:     if (!$source) {
  657: 	my @idx = &math_random_permuted_index($destct);
  658: 	my $ctr = 0;
  659: 	my @r_idx;
  660: 	while ($ctr < $destct) {
  661: 	    $r_idx[$idx[$ctr]] = $ctr;
  662: 	    $ctr++;
  663: 	}
  664: 	my @output;
  665: 	$ctr = 0;
  666: 	while ($ctr < $destct) {
  667: 	    $output[$ctr] = $$dest[$r_idx[$ctr]];
  668: 	    $ctr++;
  669: 	}
  670:         &random_set_seed(@oldseed);
  671: 	return @output;
  672:     } else {
  673: 	my $num = scalar(@$source);
  674: 	my @idx = &math_random_permuted_index($num);
  675: 	my $ctr = 0;
  676: 	my $tot = $num;
  677: 	$tot = $destct if $destct < $num;
  678: 	my @r_idx;
  679: 	while ($ctr < $tot) {
  680: 	    $r_idx[$idx[$ctr]] = $ctr;
  681: 	    $ctr++;
  682: 	}
  683: 	$ctr = 0;
  684: 	if (ref($$dest[0])) {
  685: 	    while ($ctr < $tot) {
  686: 		${$$dest[$ctr]} = $$source[$r_idx[$ctr]];
  687: 	        $ctr++;
  688:             }
  689:         } else {
  690: 	    while ($ctr < $tot) {
  691: 		$$dest[$ctr] = $$source[$r_idx[$ctr]];
  692: 		$ctr++;
  693: 	    }
  694: 	}
  695:     }
  696:     &random_set_seed(@oldseed);
  697:     return '';
  698: }
  699: 
  700: sub capa_id { return }
  701: 
  702: sub problem { return }
  703: 
  704: sub name{
  705:     my $fullname = &EXT('environment.lastname').', '.&EXT('environment.firstname').' '.&EXT('environment.middlename');
  706:     $fullname = "" if $fullname eq ",  ";
  707:     $fullname =~ s/\%2d/-/g;
  708:     return $fullname;
  709: }
  710: 
  711: sub student_number { 
  712:     my $id = &EXT('environment.id');
  713:     $id = '' if $id eq "";
  714:     return $id;
  715: }
  716: 
  717: sub class {
  718:     my $course = &EXT('course.description');
  719:     $course = '' if $course eq "";
  720:     return $course;
  721: }
  722: 
  723: sub sec { 
  724:     my $sec = &EXT('request.course.sec');
  725:     $sec = '' if $sec eq "";
  726:     return $sec;
  727: }
  728: 
  729: sub open_date { 
  730:     my @dc = split(/\s+/,localtime(&EXT('resource.0.opendate')));
  731:     return '' if ($dc[0] eq "Wed" and $dc[2] == 31 and $dc[4] == 1969);
  732:     my @hm = split(/:/,$dc[3]);
  733:     my $ampm = " am";
  734:     if ($hm[0] > 12) {
  735: 	$hm[0]-=12;
  736: 	$ampm = " pm";
  737:     }
  738:     return $dc[0].', '.$dc[1].' '.$dc[2].', '.$dc[4].' at '.$hm[0].':'.$hm[1].$ampm;
  739: }
  740: 
  741: sub due_date { 
  742:     my @dc = split(/\s+/,localtime(&EXT('resource.0.duedate')));
  743:     return '' if ($dc[0] eq "Wed" and $dc[2] == 31 and $dc[4] == 1969);
  744:     my @hm = split(/:/,$dc[3]);
  745:     my $ampm = " am";
  746:     if ($hm[0] > 12) {
  747: 	$hm[0]-=12;
  748: 	$ampm = " pm";
  749:     }
  750:     return $dc[0].', '.$dc[1].' '.$dc[2].', '.$dc[4].' at '.$hm[0].':'.$hm[1].$ampm;
  751: }
  752: 
  753: sub answer_date { 
  754:     my @dc = split(/\s+/,localtime(&EXT('resource.0.answerdate')));
  755:     return '' if ($dc[0] eq "Wed" and $dc[2] == 31 and $dc[4] == 1969);
  756:     my @hm = split(/:/,$dc[3]);
  757:     my $ampm = " am";
  758:     if ($hm[0] > 12) {
  759: 	$hm[0]-=12;
  760: 	$ampm = " pm";
  761:     }
  762:     return $dc[0].', '.$dc[1].' '.$dc[2].', '.$dc[4].' at '.$hm[0].':'.$hm[1].$ampm;
  763: }
  764: 
  765: sub array_moments {
  766:     my @input=@_;
  767:     my (@output,$N);
  768:     $N=scalar (@input);
  769:     $output[0]=$N;
  770:     if ($N <= 1) {
  771: 	$output[1]=$input[0];
  772: 	$output[1]="Input array not defined" if ($N == 0);
  773: 	$output[2]="variance undefined for N<=1";
  774: 	$output[3]="skewness undefined for N<=1";
  775: 	$output[4]="kurtosis undefined for N<=1";
  776: 	return @output;
  777:     }
  778:     my $sum=0;
  779:     foreach my $line (@input) {
  780: 	$sum+=$line;
  781:     }
  782:     $output[1] = $sum/$N;
  783:     my ($x,$sdev,$var,$skew,$kurt) = 0;
  784:     foreach my $line (@input) {
  785: 	$x=$line-$output[1];
  786: 	$var+=$x**2;
  787: 	$skew+=$x**3;
  788: 	$kurt+=$x**4;
  789:     }
  790:     $output[2]=$var/($N-1);
  791:     $sdev=CORE::sqrt($output[2]);
  792:     if ($sdev == 0) {
  793: 	$output[3]="inf-variance=0";
  794: 	$output[4]="inf-variance=0";
  795: 	return @output;
  796:     }
  797:     $output[3]=$skew/($sdev**3*$N);
  798:     $output[4]=$kurt/($sdev**4*$N)-3;
  799:     return @output;
  800: }
  801: 
  802: sub choose {
  803:     my $num = $_[0];
  804:     return $_[$num];
  805: }
  806: 
  807: # expiremental idea
  808: sub proper_path {
  809:     my ($path)=@_;
  810:     if ( $external::target eq "tex" ) {
  811: 	return '/home/httpd/html'.$path;
  812:     } else {
  813: 	return $path;
  814:     }
  815: }
  816: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>