Module:Sandbox/Johnuniq/grosstonnage

Source: Wikipedia, the free encyclopedia.
-- Test idea from Wnt to convert GT (gross tonnage) to/from volume.
-- Usage: {{#invoke:Sandbox/Johnuniq/grosstonnage | run_tests | vol1 | vol2 | step}}
-- where parameters vol1, vol2, step are optional numbers.
-- Using {{#invoke:sandbox/Johnuniq/grosstonnage | run_tests}}
-- sets vol1 = 0, vol2 = 100,000, step = 1000
-- which outputs results from 0 to 100,000 cubic meters, in steps of 1000.
--
-- In the debug console, can do quick calculations:
-- =p.gt(10000)
-- =p.vol(2800)

local abs = math.abs
local log10 = math.log10

local function collection()
    -- Return a table to hold lines of text.
    return {
        n = 0,
        add = function (self, s)
            self.n = self.n + 1
            self[self.n] = s
        end,
        join = function (self, sep)
            return table.concat(self, sep or '\n')
        end,
    }
end

local function gross_tonnage(volume)
    -- Return GT equivalent to given volume in cubic meters.
    -- GT = (0.2 + 0.02 * log10(cubic_meters)) * cubic_meters
    if volume > 0 then
        return (0.2 + 0.02 * log10(volume)) * volume
    end
    return 0
end

local function volume_from_gt(gross_tonnage)
    -- Return volume in cubic meters equivalent to given gross tonnage.
    -- GT = (0.2 + 0.02 * log10(cubic_meters)) * cubic_meters
    if gross_tonnage <= 0 then
        return 0
    end
    local k_factor = 0.20
    local volume = gross_tonnage / k_factor
    for i = 1, 100 do
        k_factor = 0.20 + 0.02 * log10(volume)
        local new_volume = gross_tonnage / k_factor
        if abs(new_volume - volume) < 0.1 then
            return new_volume, i  -- also return i for curiosity
        end
        volume = new_volume
    end
    print('Bug: Too many iterations')
    return 0
end

local function run_tests(frame)
    local args = frame.args
    local vol1 = tonumber(args[1]) or 0
    local vol2 = tonumber(args[2]) or 1e5
    local step = tonumber(args[3]) or 1000
    local results = collection()
    results:add('<pre>')
    results:add('   Vol_input    Gross_ton    Vol_output  Iter')
    for v = vol1, vol2, step do
        local gt = gross_tonnage(v)
        local vout, iterations = volume_from_gt(gt)
        results:add(string.format('%12.2f %12.2f %12.5f %3d', v, gt, vout, iterations or 0))
    end
    results:add('</pre>')
    return results:join()
end

return { gt = gross_tonnage, vol = volume_from_gt, run_tests = run_tests }