Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Sheetworker Integer from RepeatingSum

Greetings. I have a sheetworker that is doing a RepeatingSum calculation. For some reason, it "sometimes" gives a result like the value shown below: 60.50000000000001 Other times, it works just fine. I have manually added the figures in the RepeatingSum, and in the case of the example above the correct result is 60.50, so I don't need any of the digits after the second decimal place. How can I round the value to two decimal points? I have tried using the step="0.01" command, but this does not work. I am using the RepeatingSum directly from the Wiki...
1564373050
GiGs
Pro
Sheet Author
API Scripter
This is likely just because of the way computers, or the specific javascript implementation, rounds numbers. There's no simple fix. I do have an idea for adding a way to add config options to repeatingSum (like whetehr to use integers, or round to specific digits). Until I do that, the easiest solution is to use an intermediate attribute. have repeatingSum set a hidden attribute. Then have that attribute have a sheet worker attached that rounds off to two digits. The calculation would be (pseudocode) for 2 digits: output = Math.round(input * 100)/100;
GiGs said: This is likely just because of the way computers, or the specific javascript implementation, rounds numbers. There's no simple fix. I do have an idea for adding a way to add config options to repeatingSum (like whetehr to use integers, or round to specific digits). Until I do that, the easiest solution is to use an intermediate attribute. have repeatingSum set a hidden attribute. Then have that attribute have a sheet worker attached that rounds off to two digits. The calculation would be (pseudocode) for 2 digits: output = Math.round(input * 100)/100; Thanks GiGs...I'll think on that one  :)
1564374608
GiGs
Pro
Sheet Author
API Scripter
Here's a quick hack of the script to test: const repeatingSum = (destination, section, fields, config = {}) => { if (!Array.isArray(fields)) fields = [fields]; getSectionIDs(`repeating_${section}`, idArray => { const attrArray = idArray.reduce( (m,id) => [...m, ...(fields.map(field => `repeating_${section}_${id}_${field}`))],[]); getAttrs(attrArray, v => { console.log("===== values of v: "+ JSON.stringify(v) +" ====="); // getValue: if not a number, returns 1 if it is 'on' (checkbox), otherwise returns 0.. const getValue = (section, id,field) => parseFloat(v[`repeating_${section}_${id}_${field}`], 10) || (v[`repeating_${section}_${id}_${field}`] === 'on' ? 1 : 0); let sumTotal = idArray.reduce((total, id) => total + fields.reduce((subtotal,field) => subtotal * getValue(section, id,field),1),0); if(config && config.round) sumTotal = Math.round(sumTotal * Math.pow(10,config.round ||0 ) ) / Math.pow(10,config.round ||0 ); else if(config && config.floor) sumTotal = Math.floor(sumTotal * Math.pow(10,config.round ||0 ) ) / Math.pow(10,config.floor ||0 ); else if(config && config.ceil) sumTotal = Math.ceil(sumTotal * Math.pow(10,config.ceil ||0 ) ) / Math.pow(10,config.ceil ||0 ); if(config && config.multiplier) sumTotal = sumTotal * config.multiplier; setAttrs({[destination]: sumTotal}); }); }); }; Add a fourth paremeter, enclosed in curly brackets, with the type of rounding, and the number of digits to round to: For instance, if you have a repeating_inventory, are multiplying quantity and weight together, and saving to a total_weight attribute, and wanted to round to two decimals, you'd use: repeatingSum('total_weight', 'inventory', ['quantity', 'weight'], {round: 2}); Give that a try. 
GiGs said: Here's a quick hack of the script to test: const repeatingSum = (destination, section, fields, config = {}) => { if (!Array.isArray(fields)) fields = [fields]; getSectionIDs(`repeating_${section}`, idArray => { const attrArray = idArray.reduce( (m,id) => [...m, ...(fields.map(field => `repeating_${section}_${id}_${field}`))],[]); getAttrs(attrArray, v => { console.log("===== values of v: "+ JSON.stringify(v) +" ====="); // getValue: if not a number, returns 1 if it is 'on' (checkbox), otherwise returns 0.. const getValue = (section, id,field) => parseFloat(v[`repeating_${section}_${id}_${field}`], 10) || (v[`repeating_${section}_${id}_${field}`] === 'on' ? 1 : 0); let sumTotal = idArray.reduce((total, id) => total + fields.reduce((subtotal,field) => subtotal * getValue(section, id,field),1),0); if(config && config.round) sumTotal = Math.round(sumTotal * Math.pow(10,config.round ||0 ) ) / Math.pow(10,config.round ||0 ); else if(config && config.floor) sumTotal = Math.floor(sumTotal * Math.pow(10,config.round ||0 ) ) / Math.pow(10,config.floor ||0 ); else if(config && config.ceil) sumTotal = Math.ceil(sumTotal * Math.pow(10,config.ceil ||0 ) ) / Math.pow(10,config.ceil ||0 ); if(config && config.multiplier) sumTotal = sumTotal * config.multiplier; setAttrs({[destination]: sumTotal}); }); }); }; Add a fourth paremeter, enclosed in curly brackets, with the type of rounding, and the number of digits to round to: For instance, if you have a repeating_inventory, are multiplying quantity and weight together, and saving to a total_weight attribute, and wanted to round to two decimals, you'd use: repeatingSum('total_weight', 'inventory', ['quantity', 'weight'], {round: 2}); Give that a try.  Holy moly GiGs....you're a machine  :o
1564376179
GiGs
Pro
Sheet Author
API Scripter
Thanks :) Handy tip: if you give it a negative number e.g. {round: -3} it will round to, say, thousands. 34567 would become 35,000. I'm not sure who would find this would be useful, but someone might!