【问题标题】:Using the original values of a vector after manipulation操作后使用向量的原始值
【发布时间】:2018-04-05 13:02:06
【问题描述】:

我正在尝试将从文件接收的矢量值转换为两种不同的格式。转换为第一种格式并打印出矢量后,我想使用原始的“读入”值将它们转换为第二种格式。

目前,似乎第二次转换发生在已转换的值上。但是,我不明白为什么它不转换回原始值呢?最终,我怎样才能使用向量的原始值进行第二次转换,所以

else {
        GetType();
        GetXArg();
        GetYArg();
    }

第二次工作?

这里是sn-p的代码:

void Force::convToP()  //converts to polar
{
    if (forceType == 'c')
    {
        SetType('p');
        SetXArg(sqrt(xArg * xArg + yArg * yArg));
        SetYArg(atan(yArg / xArg));
    }
    else {
        GetType();  //just return type, xArg and yArg in their original form
        GetXArg();
        GetYArg();
    }

}

void Force::convToC()  //converts to cartesian
{
    if (forceType == 'p') {
        SetType('c');
        SetXArg(xArg * cos(yArg));
        SetYArg(xArg * sin(yArg));
    }
    else {
        GetType();
        GetXArg();
        GetYArg();
    }
}

及主要功能:

while (file >> type >> x >> y) {
        Force f(type, x, y);
        force.push_back(f);
    }
    for (int i = 0; i < force.size(); ++i) {
        force[i].printforce();
    }

    cout << "Forces in Polar form: " << endl;
    for (int i = 0; i < force.size(); ++i)
    {
        force[i].convToP();
        force[i].printforce();
    }

    cout << "Forces in Cartesian form: " << endl;
    for (int i = 0; i < force.size(); ++i) {
        force[i].convToC();
        force[i].printforce();
    }

最后,此刻的输出是:

p 10 0.5
c 12 14
p 25 1
p 100 0.8
c 50 50
p 20 3.14
c -100 25
p 12 1.14

Forces in Polar form:  <-first conversion. All works fine

p 10 0.5  
p 18.4391 0.649399
p 25 1
p 100 0.8
p 70.7107 0.61548
p 20 3.14
p 103.078 0.237941
p 12 1.14

Forces in Cartesian form:

c 8.77583 4.20736 <-works fine
c 14.6858 8.8806  <-why doesn't convert back to c 12 14/ how to use the original values of vector
c 13.5076 11.3662
c 69.6707 49.9787
c 57.735 33.3333
c -20 -0.0318509
c 100.173 23.6111
c 5.01113 4.55328
Press any key to continue . . .

对此非常陌生,困惑了一段时间,因此非常感谢任何帮助和建议。

【问题讨论】:

  • 请提供minimal reproducible example。例如,在您的代码中,不清楚所有GetXArg(); 在做什么。顺便说一句,如果您执行 a = foo(a); 之类的操作,您将如何获得 a 的原始值?
  • @user463035818 所有Get 函数只返回xArgyArgfType
  • 是的,我看到了评论,但这让我更加困惑,因为如果那些 Get 函数返回一些东西,那么你就忽略返回的值......
  • MCVE 不是“这里有一些代码片段和对缺失位的通俗描述”。
  • 通过手动检查c 50 50,你得到了p 70.7107 0.61548,但atan(1)0.785398...

标签: c++ vector


【解决方案1】:

您正在修改xArg,然后使用修改后的值转换yArg。您需要在修改之前进行两次转换。

void Force::convToP()  //converts to polar
{
    if (forceType == 'c')
    {
        forceType = 'p';
        decltype(xArg) newX = sqrt(xArg * xArg + yArg * yArg);
        decltype(yArg) newY = atan(yArg / xArg);
        xArg = newX;
        yArg = newY
    }
    // no else needed
}

void Force::convToC()  //converts to cartesian
{
    if (forceType == 'p') {
        forceType = 'c';
        decltype(xArg) newX = xArg * cos(yArg);
        decltype(yArg) newY = xArg * sin(yArg);
        xArg = newX;
        yArg = newY
    }
    // no else needed
}

您可以使用std::complex 验证the correct values

#include <complex>
#include <vector>
#include <iostream>

int main() {

    std::vector<std::complex<double>> nums
    {
        std::polar<double>(10, 0.5),
        std::complex<double>(12, 14),
        std::polar<double>(25, 1),
        std::polar<double>(100, 0.8),
        std::complex<double>(50, 50),
        std::polar<double>(20, 3.14),
        std::complex<double>(-100, 25),
        std::polar<double>(12, 1.14)
    };

    for (auto num : nums) 
    { 
        std::cout << num << " (" << std::abs(num) << ", " << std::arg(num) << ")\n";
    }
}
(8.77583,4.79426) (10, 0.5)
(12,14) (18.4391, 0.86217)
(13.5076,21.0368) (25, 1)
(69.6707,71.7356) (100, 0.8)
(50,50) (70.7107, 0.785398)
(-20,0.0318531) (20, 3.14)
(-100,25) (103.078, 2.89661)
(5.01113,10.9036) (12, 1.14)

【讨论】:

  • 在第一次转换中发现All works fine 出错了
  • @UKMonkey 我的猜测是 OP 看了看数字并看到“这里有一些小数,一定是正确的”,并且没有独立检查
  • @Caleth @UKMonkey 太忙了,看不到如何使用原件,注意到 xArg 在第二次使用之前被修改了。明智的格式看起来不错,所以没有点击。感谢您注意到错误
【解决方案2】:

将子操作分解为小的单一关注功能通常很有帮助。

编译器会优化掉所有多余的副本、加载和存储:

#include <cmath>
#include <tuple>

auto computed(double xArg, double yArg) 
{
    return 
        std::make_tuple(
            std::sqrt(xArg * xArg + yArg * yArg),
            std::atan(yArg / xArg));
}

void modify(double& xArg, double& yArg)
{
    std::tie(xArg, yArg) = computed(xArg, yArg);
}

【讨论】:

    【解决方案3】:

    在不知道GetXArg() 等具体做什么的情况下,当您调用force[i].convToP(); 时,您似乎正在修改您的原始力量。因此,在此循环之后,阵列中的所有力都转换为极坐标。如果您只想在不更改原件的情况下打印极坐标和笛卡尔表示,您应该生成力的副本:

    cout << "Forces in Polar form: " << endl;
    for (int i = 0; i < force.size(); ++i)
    {
        Force tmpForce = force[i];
        tmpForce.convToP();
        tmpForce.printforce();
    }
    

    等等

    编辑:看起来@Aconcagua 打败了我。

    【讨论】:

      【解决方案4】:

      你的转换函数显然改变了它操作的对象。然后您需要注意,索引运算符 ([]) 返回向量中对象的 reference。如果您不想修改原始对象,则必须复制:

      for (int i = 0; i < force.size(); ++i)
      {
          auto copy = force[i]
          copy.convToP();
          copy.printforce();
      }
      

      现在,您可以在第二次运行中对未更改的值进行操作。假设您不再需要原始值,您可以保持第二个循环不变,否则,再次制作副本...

      使用基于范围的 for 循环会更容易一些:

      for(auto c : force)
      {
          c.convToP();
          c.printforce();
      }
      
      for(auto& c : force)
      //      ^ if you don't need original values any more, can use reference now
      {
          c.convToC();
          c.printforce();
      }
      

      【讨论】:

      • 作为安全检查,最好还添加operator[]const 重载,然后使用基于范围的for 循环对const 对象进行操作。这样一来,如果你不小心尝试修改它们,它将无法编译。
      • @0x5453 那么您希望convToX() 函数如何工作?
      • @MaxLanghof 查看我的编辑。他仍然需要制作副本,但这样编译器将强制他不能修改原始对象。
      • @Aconcagua 非常感谢你,这正是我想要的,但不知道该怎么做!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-26
      • 2015-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多