【问题标题】:How to calculate square root in sqlite如何在sqlite中计算平方根
【发布时间】:2012-09-25 18:21:47
【问题描述】:

我需要在 sqlite 数据库中计算欧几里得距离。

除了为数学函数编写和加载动态库之外,有谁知道如何在 sqlite 中计算平方根?

我即将在http://en.wikipedia.org/wiki/Fast_inverse_square_root 中使用快速逆平方根算法,尽管它可能会变得比我现在需要的更有趣。

顺便说一句,弄清楚如何做功率会很棒(这是一个笼统的问题,编码比将一个数字本身相乘更简洁)。

谢谢,

西蒙娜

【问题讨论】:

  • 它必须有多准确?
  • 使用extension functionHere 是一个关于它的线程。
  • 比较欧几里得距离时,您可以将两边取平方而不是平方根 - 幂可能看起来像更简洁的代码,但通常比对数更慢,尽管还有其他积分幂的方法
  • 我认为 SQLite 也不支持 power。
  • 原生SQLite确实不支持Power。

标签: sql sqlite math


【解决方案1】:

好吧,我有一个半答案。

是的,它涉及第 3 方,但您不必自己编写:您是否检查了 this page 上的最后一个扩展名?

它包括几个数学函数,其中包括 sqrt()。

【讨论】:

  • 我实际上想避免使用扩展。但是,我很感激您的回答促使我尝试了它-结果比我想象的要容易,现在我知道如何解决下一个类似问题。谢谢
【解决方案2】:

据我所知 - 仅使用核心功能是无法做到这一点的。

这里是原生函数列表Core functions 和聚合函数列表Aggregate functions

为了解决您的问题,您可以编写自己的UDF(用户定义函数),如图HERE

【讨论】:

    【解决方案3】:

    警告:此答案取决于编码语言。在我的例子中 C#

    用户定义的 SQLite 函数对我来说实现起来很痛苦。最后,经过长时间的搜索,我能够在我的 C# 代码中实现它。主函数如下所示:

    [SQLiteFunction(Arguments = 1, FuncType = FunctionType.Scalar, Name = "Sqrt")]
    class Sqrt : SQLiteFunction
    {
        public override object Invoke(object[] args)
        {
            return Math.Sqrt(Double.Parse(args[0].ToString()));
        }
    }
    

    自定义函数的注册:

    SQLiteFunction.RegisterFunction(typeof(Sqrt));
    

    并在选择中使用:

    SQLiteCommand com = new SQLiteCommand("select sqrt(10.42)", connection);
    

    你可以在这里下载完整的例子:http://db.tt/qzeNXwso

    或者,如果您只想查看代码(或浏览我的代码的所有部分),我将在 SQLite 数据库中计算平方根的完整工作示例代码粘贴在下面,因为很难找到任何工作代码。要创建和运行此示例,请执行以下 6 个步骤:

    1. 新建项目(我叫 Sqrt)
    2. 在您的项目中包含 SQLite 引用:
      解决方案资源管理器 -> 引用(右键单击:添加引用)-> 程序集 - 扩展 - System.Data.SQLite(检查)-> 确定
    3. 打开App.config并替换成这个(没有这一步你可能会得到混合模式组装错误):

      <?xml version="1.0" encoding="utf-8" ?>
      <configuration>
      <startup useLegacyV2RuntimeActivationPolicy="true">
      <supportedRuntime version="v4.0"/>
      </startup>
      </configuration>

    4. 用以下代码替换您的 Form1.Designer.cs

      namespace Sqrt
      {
       partial class Form1
       {
       /// <summary>
       /// Required designer variable.
       /// </summary>
       private System.ComponentModel.IContainer components = null;
      
       /// <summary>
       /// Clean up any resources being used.
       /// </summary>
       /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
       protected override void Dispose(bool disposing)
       {
          if (disposing && (components != null))
          {
              components.Dispose();
          }
          base.Dispose(disposing);
       }
      
       #region Windows Form Designer generated code
      
       /// <summary>
       /// Required method for Designer support - do not modify
       /// the contents of this method with the code editor.
       /// </summary>
       private void InitializeComponent()
       {
          this.txb_Input = new System.Windows.Forms.TextBox();
          this.txb_Output = new System.Windows.Forms.TextBox();
          this.label1 = new System.Windows.Forms.Label();
          this.label2 = new System.Windows.Forms.Label();
          this.btn_Calcualte = new System.Windows.Forms.Button();
          this.SuspendLayout();
          // 
          // txb_Input
          // 
          this.txb_Input.Location = new System.Drawing.Point(131, 12);
          this.txb_Input.Name = "txb_Input";
          this.txb_Input.Size = new System.Drawing.Size(201, 20);
          this.txb_Input.TabIndex = 0;
          // 
          // txb_Output
          // 
          this.txb_Output.BackColor = System.Drawing.Color.WhiteSmoke;
          this.txb_Output.Location = new System.Drawing.Point(131, 38);
          this.txb_Output.Name = "txb_Output";
          this.txb_Output.ReadOnly = true;
          this.txb_Output.Size = new System.Drawing.Size(201, 20);
          this.txb_Output.TabIndex = 0;
          // 
          // label1
          // 
          this.label1.AutoSize = true;
          this.label1.Location = new System.Drawing.Point(12, 15);
          this.label1.Name = "label1";
          this.label1.Size = new System.Drawing.Size(31, 13);
          this.label1.TabIndex = 1;
          this.label1.Text = "Input";
          // 
          // label2
          // 
          this.label2.AutoSize = true;
          this.label2.Location = new System.Drawing.Point(12, 41);
          this.label2.Name = "label2";
          this.label2.Size = new System.Drawing.Size(39, 13);
          this.label2.TabIndex = 1;
          this.label2.Text = "Output";
          // 
          // btn_Calcualte
          // 
          this.btn_Calcualte.Location = new System.Drawing.Point(257, 64);
          this.btn_Calcualte.Name = "btn_Calcualte";
          this.btn_Calcualte.Size = new System.Drawing.Size(75, 23);
          this.btn_Calcualte.TabIndex = 2;
          this.btn_Calcualte.Text = "Calculate";
          this.btn_Calcualte.UseVisualStyleBackColor = true;
          // 
          // Form1
          // 
          this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
          this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
          this.ClientSize = new System.Drawing.Size(344, 98);
          this.Controls.Add(this.btn_Calcualte);
          this.Controls.Add(this.label2);
          this.Controls.Add(this.label1);
          this.Controls.Add(this.txb_Output);
          this.Controls.Add(this.txb_Input);
          this.Name = "Form1";
          this.Text = "Root square example";
          this.ResumeLayout(false);
          this.PerformLayout();
       }
       #endregion
      
       private System.Windows.Forms.TextBox txb_Input;
       private System.Windows.Forms.TextBox txb_Output;
       private System.Windows.Forms.Label label1;
       private System.Windows.Forms.Label label2;
       private System.Windows.Forms.Button btn_Calcualte;
       }
      }
      
    5. 打开 Form1.cs(代码)并将代码替换为: 使用系统; 使用 System.Data.SQLite; 使用 System.Windows.Forms;

      namespace Sqrt
      {
          // definition of custom sqlite function
          [SQLiteFunction(Arguments = 1, FuncType = FunctionType.Scalar, Name = "Sqrt")]
          class Sqrt : SQLiteFunction
          {
              public override object Invoke(object[] args)
              {
                  return Math.Sqrt(Double.Parse(args[0].ToString())); // return result of math sqrt function
              }
          }
      
          public partial class Form1 : Form
          {
              public Form1()
              {
                  InitializeComponent();
                  this.btn_Calcualte.Click += new System.EventHandler(this.btn_Calcualte_Click);
              }
      
              private void btn_Calcualte_Click(object sender, EventArgs e)
              {
                  if (txb_Input.Text.Length == 0)
                      return;
                  try { SQLiteConnection.CreateFile(AppDomain.CurrentDomain.BaseDirectory + "test.s3db"); }
                  catch { }
                  SQLiteConnection con = new SQLiteConnection("Data Source=test.s3db");
                  SQLiteFunction.RegisterFunction(typeof(Sqrt)); // register custom function
                  con.Open();
                  SQLiteCommand com = new SQLiteCommand("select sqrt(" + txb_Input.Text.Replace(',', '.') + ")", con); // select result
                  string res = com.ExecuteScalar().ToString();
                  txb_Output.Text = res;
              }
          }
      }
      
    6. 跑步,尝试并享受。

    【讨论】:

    • 这部分Double.Parse(args[0].ToString()) 是否用于处理错误类型的值?
    【解决方案4】:

    这是 10000 以下数字的 sqrt 近似值。它可以扩展到任意数字,并且可以根据需要扩展到任意精度。无论如何,这种表格插值在大多数快速实现中都会发生:

    case when weight >= 1 and weight<=10 then 1+0.240253073*(weight-1) 
         when weight>=10 and weight<=100 then 3.16227766+0.075974693*(weight-10) 
         when weight>=100 and weight<=1000 then 10+0.024025307*(weight-100)      
         else 31.6227766+0.007597469 *(weight-1000) end
    

    还有一个奇怪的事实是,您在这种 10 次方根插值表中使用的每个因子都是前一个插值表的 0.316227766 倍 - 因此您可以使这个数字适用于任意大的数字,甚至可以将表格填满这些值使其适用于任何数字。 (这会导致这里的一些压缩吗?)

    或者这个可爱的 log10 整数,使用长度函数(插值表在这里可能会更好,但我喜欢 log10 和 length() 是相似的,这适用于任何整数 - 不需要插值。

     ((length(x)+length(x*2)+length(x*3)
      +length(x*4)+length(x*5))/5.0)-1.0
    

    一个比我更好的数学头脑可能会想出更好和更密集的近似值。考虑到 c 中的大多数 sqrt 函数无论如何都使用近似值 - 这是一个非常好的解决方案。

    这是唯一的原生方式。

    【讨论】:

    • 如果 weight 是 9,那么表达式的结果是 2.922,如果 weight 是 16,结果是 3.618 我期待的结果更接近 3 和 4。你能解释一下你的公式和级别错误?
    • 1.打开一个excel表,2.计算平方根,3.对一组任意权重进行线性插值。上面的论坛是非常近似。你可以做得更好
    【解决方案5】:

    2021-03-12 (3.35.0)

    添加了内置 SQL 数学函数()。 (需要 -DSQLITE_ENABLE_MATH_FUNCTIONS 编译时选项。)

    Built-In Mathematical SQL Functions

    sqrt(X) 返回 X 的平方根。如果 X 为负数,则返回 NULL。

    【讨论】:

      【解决方案6】:

      只有在数学函数不可用的情况下......而且真的只是在绝望中,因为这不会很快......

      -- bisect to find the square root to any tolerance desired
      with 
       input(n) as (select 500), --input
       sqrt(lo, hi, guess, n, i) as (
        select 1, n, n/2, n, 0 from input
        union all
        select case when guess*guess < n then guess else lo end,
               case when guess*guess < n then hi else guess end,
               case when guess*guess < n then (hi+guess)/2.0 else (lo+guess)/2.0 end,
               n ,
               i +1 from sqrt
               where abs(guess*guess - n) > 0.0001), -- tolerance
       sqrt_out(x, n) as (select guess, n from sqrt order by sqrt.i desc limit 1)
       select * from sqrt_out
      

      【讨论】:

      • 这太棒了!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-31
      • 2014-01-28
      • 2021-01-04
      • 1970-01-01
      • 2021-08-03
      • 2021-05-08
      相关资源
      最近更新 更多