【问题标题】:Calculating the subsegments of a line, using logarithmic scaling使用对数缩放计算线的子段
【发布时间】:2018-04-30 09:42:28
【问题描述】:

我想计算长度为totalLineLength 的行的子段的长度,其中子段与给定事件的日志成正比。

视觉表示:|---|-----|---------|由子段组成的行。

我希望计算的子段的总和等于totalLineLength,并且必须打印SuccessLog(x+1) 也必须使用(因为它总是会为肯定的论点提供肯定的结果,并且比例也为 1)。

使用线性缩放,我正在这样做,它可以工作。

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");
}

使用 log(x+1) (calcSubSegment 更新),它不起作用。

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");
}

我的代码有什么问题?我想是 eventTotal 计算,但我不确定如何进行。

我应该如何使用对数缩放?我也想要一个数学解释。

【问题讨论】:

  • log(0.1 + 1) + log(1 + 1) * log(22 + 1) = log(1.1*2*23) = log(50.6)log(0.1 + 1 + 22 + 1) = log(24.1)。这应该如何等于线性情况?请详细说明您的期望。
  • 子段的长度不必等于线性情况,但它们的总和必须等于totalLineLength。我不明白你为什么要对 log(x+1) 求和,其中 x 是事件。
  • 我认为这是你所做的。
  • 我和 log(x+1) / log(eventTotal+1) not log(x+1)
  • 好的。因素log(eventTotal+1),因为它对所有人都是一样的。然后,你总结log(x+1)。对吗?

标签: javascript math logarithm


【解决方案1】:

如果我正确理解您的任务,最简单的解决方案是首先使用您的 events 函数 map all events 然后使用您已经实现的线性拆分。像这样的:

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"); 

这个想法是唯一的分裂

  1. 具有与某些系数成比例的部分
  2. 使所有部分的总和等于整体

同时是线性分裂。因此,如果您想以任何方式缩放系数,则应在传递给线性拆分逻辑之前对其进行缩放。否则,部分的总和将不等于代码中发生的整体(在任何非线性缩放的情况下)。

附:通过== 比较浮点值并不是一个好主意。您应该对计算/舍入误差使用一些容忍度。

【讨论】:

    【解决方案2】:

    处理对数时的重要规则:log(a)+log(b) = log(a*b)。因此,为了计算总长度,我们需要找到各个数字的乘积而不是它们的总和。

    1. 您所做的是显示log(a)+log(b) != log(a+b),因此请尝试将数字相乘而不是相加。

    2. 由于浮点运算的工作方式,请使用SergGr's answer 中所述的误差范围。

    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);
    }

    【讨论】:

      猜你喜欢
      • 2021-07-10
      • 2020-08-02
      • 2010-12-07
      • 1970-01-01
      • 2018-09-04
      • 1970-01-01
      • 2015-11-14
      • 2016-07-23
      • 1970-01-01
      相关资源
      最近更新 更多