Calculating the subsegments of a line, using logarithmic scaling

五迷三道 提交于 2019-12-23 16:15:31

问题


I want to calculate the length of the subsegments of a line having a length of totalLineLength, where the subsegments are proportional to the log of the events given.

A visual representation: |---|-----|---------| a line composed of subsegments.

I want the sum of the calculated subsegments to be equal to totalLineLength, and Success must be printed. Log(x+1) must be used too (because it gives always positive results for positive arguments and scales 1 too).

Using linear scaling, I'm doing this, and it works.

var totalLineLength = 20;
var eventTotal;
var calcSubSegment = function(x) {
    return totalLineLength * x / eventTotal;
}

var events = [0.1, 1, 22];
eventTotal = events.reduce((a, b) => a + b, 0);
var subSegments = events.map(calcSubSegment);
var segmentLength = subSegments.reduce((a, b) => a + b);
if (segmentLength != totalLineLength) {
    console.log("Error:", segmentLength);
} else {
    console.log("Success");
}

Using log(x+1) (calcSubSegment is updated), it doesn't work.

var totalLineLength = 20;
var eventTotal;
var calcSubSegment = function(x) {
    return totalLineLength * Math.log(x+1) / Math.log(eventTotal+1);
}

var events = [0.1, 1, 22];
eventTotal = events.reduce((a, b) => a + b, 0);
var subSegments = events.map(calcSubSegment);
var segmentLength = subSegments.reduce((a, b) => a + b, 0);
if (segmentLength != totalLineLength) {
    console.log("Error:", segmentLength);
} else {
    console.log("Success");
}

What's wrong with my code? I suppose the eventTotal calculation, but I'm not sure how to proceed.

How should I use logarithmic scaling? I'd also like a mathematical explanation.


回答1:


If I understand your task correctly, the simplest solution is first map all events using your log(x+1) functions and then just use linear split you've already implemented. Something like this:

function linearSplit(events, totalLineLength) {
	var eventTotal;
	var calcSubSegment = function(x) {
		return totalLineLength * x / eventTotal;
	}

	eventTotal = events.reduce((a, b) => a + b, 0);
	var subSegments = events.map(calcSubSegment);
	return subSegments;
}


function logSplit(events, totalLineLength) {
	var logEvents = events.map(function(x) { return Math.log(x+1); } );
	return linearSplit(logEvents, totalLineLength);
}



function testSplit(events, totalLineLength, fnSplit, splitName) {
	var subSegments = fnSplit(events, totalLineLength);
	var segmentLength = subSegments.reduce((a, b) => a + b, 0);
	console.log(splitName + ":\n"  + events + " =>\n" + subSegments);
	if (Math.abs(segmentLength - totalLineLength) > 0.001) {
		console.log(splitName + " Error:", segmentLength);
	} else {
		console.log(splitName + " Success");
	}
}

var totalLineLength = 20;
var events = [0.1, 1, 22];

testSplit(events, totalLineLength, linearSplit, "linearSplit");
testSplit(events, totalLineLength, logSplit, "logSplit"); 

The idea is that the only splitting that

  1. Has parts proportionally to some coefficients
  2. Makes sum of all parts equal to the whole

at the same time is the linear splitting. So if you want to scale coefficients in any way, you should scale them before passing to the linear splitting logic. Otherwise the sum of parts will not equal the whole (in case of any non-linear scaling) as it happens in your code.

P.S. It is not very good idea to compare floating point values by ==. You should use some tolerance for calculation/rounding errors.




回答2:


Important rule while dealing with logarithms: log(a)+log(b) = log(a*b). Hence for the calculation of the total length, we need to the find the product of the individual numbers instead of their sum.

  1. What you are doing is showing that log(a)+log(b) != log(a+b), so try multiplying the numbers instead of adding them.

  2. Use an error margin as described in SergGr's answer, because of the way floating point operations work.

var totalLineLength = 20;
var eventTotal;
var calcSubSegment = function(x) {
    return totalLineLength * Math.log(x+1) / Math.log(eventTotal);
}

var events = [0.1, 1, 22];
eventTotal = events.reduce((a, b) => a * (b+1), 1);
var subSegments = events.map(calcSubSegment);
var segmentLength = subSegments.reduce((a, b) => a + b, 0);
if (segmentLength != totalLineLength) {
    console.log("Error:", segmentLength);
} else {
    console.log("Success", subSegments);
}


来源:https://stackoverflow.com/questions/47336655/calculating-the-subsegments-of-a-line-using-logarithmic-scaling

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!