WeBWorK Problems

Number formats

Number formats

by Adam Z -
Number of replies: 14

what is an easy way to have commas after every three digits and currency or dollar sign, in my case $m may be a big number I need to show commas, $a , $b needs to show in the dollar sign, although I can add it manually. Since I am learning these scripts I must have other ways to do this formatting stuff.

DOCUMENT();        

loadMacros(

  "PGstandard.pl",

  "PGchoicemacros.pl",

  "PGgraphmacros.pl",

  "PGcourse.pl",

  "contextCurrency.pl"  #this macro for currency 

);

TEXT(beginproblem());

$showPartialCorrectAnswers = 1;

Context("Currency");

Context()->currency->set(comma=>'.',decimal=>',');

$a = non_zero_random(0,100,1);

$b = non_zero_random(0,40,1) ;

$x = non_zero_random(0,1000,1);

$y = non_zero_random(0,1000,1);

$m = $a * $x + $b * $y;

$n =  $x + $y;

$NO_SPACE = '@{}';

BEGIN_TEXT

$BR

$BR

Tickets to a Broadway show cost $$a for adults and $$b for children. The total receipts for $n tickets at one performance were $$m. How many adult and how many child tickets were sold?

$BR

$BR

Number of tickets sold for adults was =  \{ans_rule(20) \}

$BR

$BR

Number of tickets sold for children was = \{ans_rule(20) \}

END_TEXT

ANS(num_cmp($x);

ANS(num_cmp($y);

ENDDOCUMENT();     

In reply to Adam Z

Re: Number formats

by Danny Glin -

I have attached an updated version of your problem.  Here are a few notes:

  • The line
    Context()->currency->set(comma=>'.',decimal=>',');
    reverses the meaning of comma and decimal.  The default for the Currency context is to put commas after every three digits, so if you don't want to change that then you should leave this line out.
  • When you define your variables, you are not casting any of them as currency objects, so WeBWorK doesn't know that it should add commas and dollar signs.  The non_zero_random subroutine generates floating point numbers in perl.  If you want to specify that these should be dollar amounts, then you will need to add Currency() around them, e.g.
    $a = Currency(non_zero_random(0,100,1));
  • If you use PGML instead of BEGIN_TEXT/END_TEXT, it will take care of a lot of the layout stuff for you.  In particular it will deal with the number display format automatically.
  • You shouldn't use num_cmp anymore.  This is a legacy answer checker, and isn't well maintained.  If you are using BEGIN_TEXT/END_TEXT, then you can use 
    ANS(Real($x)->cmp());
    If you use PGML (as shown in the attached example), then you don't need to worry about this at all.
  • In loadMacros, best practice is always to have PGcourse.pl as the last entry.
In reply to Danny Glin

Re: Number formats

by Adam Z -
Thank you very much, this is very helpful. Can you refer to me a question/questions that use PGML so I understand better , something simple please
In reply to Adam Z

Re: Number formats

by Danny Glin -

The file I attached to my previous post is a good starting example.  You can also take a look at https://webwork.maa.org/wiki/Introduction_to_PGML.  If you have questions please post them here.

In reply to Danny Glin

Re: Number formats

by Adam Z -
Hello Danny:

I used PGML in the following example. I have a minor issue, $m in the body of the question as shown as a currency how to take $ sign off.

DOCUMENT(); # This should be the first executable line in the problem.
loadMacros(
"PGstandard.pl", # Standard macros for PG language
"MathObjects.pl",
"PGML.pl",
"contextCurrency.pl",
"PGcourse.pl",
);

TEXT(beginproblem());
Context("Currency");
$showPartialCorrectAnswers = 1;

do{$a = random(2,15,0.1);
do{$b = random(2,15,0.1);} until ($b!=$a);
$x =Currency(random(100,20000,10));
$y = Currency(random(100,20000,10));} until ($a*$x/($x+$y) + $b*$y/($x+$y) == random(2,20,0.1));
$n = ($x+$y);
$m = $a*$x/$n + $b*$y/$n;

BEGIN_PGML

Rachel had [$n] to invest and wants to earn [$m]% interest per year. She will put some of the money into an account that earns [$a]% per year and the rest into an account that earns [$b]% per year. How much money should she put into each account?

Rachel should put [_____]{$x} into the account that earns [$a]%, and [_____]{$y} into the account that earn [$b]%.

END_PGML

ENDDOCUMENT(); # This should be the last executable line in the problem.
In reply to Adam Z

Re: Number formats

by Davide Cervone -

You could either coerce the currency values into MathObject Reals using

$m = Real($a*$x/$n + $b*$y/$n);

or leave $x and $y as perl reals initially and then coerse them to Currency objects later:

do{
  $a = random(2, 15, 0.1);
  do {$b = random(2, 15, 0.1);} until ($b!=$a);
  $x = random(100, 20000, 10);
  $y = random(100, 20000, 10);
  $n = ($x+$y);
  $m = ($a*$x + $b*$y) / $n;
} until ($m == random(2, 20, 0.1));
$x = Currency($x);
$y = Currency($y);
On a separate note, I'm a bit concerned about your termination condition for the main loop, as it seems that meeting that condition will be pretty unlikely (though I haven't investigated it deeply), and so such a loop could take a long time to locate a suitable value. Shouldn't you be able to fix three of the values and solve for the fourth, rather than having to loop so much?
In reply to Davide Cervone

Re: Number formats

by Adam Z -
Just seen your answer. Thank you, this sounds great. My goal of the loop is t avoid having long decimal with too many digits form. Any other idea?
In reply to Davide Cervone

Re: Number formats

by Adam Z -
I thought having a loop for the four variables it gives more freedom to choose variables that meet this condition, what do you think?
In reply to Adam Z

Re: Number formats

by Alex Jordan -

I think your loop condition is really meant to make sure that $m is between 2 and 20, and has at most one decimal place.

Isn't $m automatically between 2 and 15, since it is a weighted average of $a and $b?

And then if you are testing that $m has at most one decimal place, you can do:

... until ($m == Round($m,1));

This still gives looping that could be avoided by either (a) putting a lot of thought into how to define the variables carefully or (b) not caring about the decimals only having one decimal place. But this would be much less looping than if the condition is ($m == random(2,20,0.1)). With that condition, when it is ready to test the condition, $m is already defined, and even if $m does have at most one decimal place, there is only a 1/(181) chance that it will equal the result from that random() call.
In reply to Alex Jordan

Re: Number formats

by Adam Z -

Thanks, Alex. Good thoughts. I will try these ideas and see how it goes. 

In reply to Alex Jordan

Re: Number formats

by Adam Z -

Round( $m,1) did not work , it gives me error . Attached is the whole question. If someone can help me give a better coding I would really appreciate this. The goal is not to have too many decimal digits. 

In reply to Adam Z

Re: Number formats

by Alex Jordan -

The way you have defined $m, it is a Currency object. (Because it is created using $a and $b which are Currency objects.) The Round function expects a plain perl real. So use:

... until ($m == Round($m->value,1));

In reply to Alex Jordan

Re: Number formats

by Adam Z -

I tried this as well, did not work. 

... until ($m == Round($m->1,1));

In reply to Adam Z

Re: Number formats

by Alex Jordan -

When I posted:

$m->value

I literally mean the string "value". That is applying a method to $m to get its per value.